2025-01-14 14:29:14 +08:00
|
|
|
|
//
|
|
|
|
|
// RoomAnimationView.m
|
|
|
|
|
// YuMi
|
|
|
|
|
//
|
|
|
|
|
// Created by P on 2025/1/13.
|
|
|
|
|
//
|
|
|
|
|
|
2025-08-15 11:41:45 +08:00
|
|
|
|
//banner 手势处理会有遮挡其他视图操作的问题
|
|
|
|
|
|
2025-01-14 14:29:14 +08:00
|
|
|
|
#import "RoomAnimationView.h"
|
|
|
|
|
|
2025-01-15 19:02:58 +08:00
|
|
|
|
#import <POP.h>
|
|
|
|
|
#import <SVGA.h>
|
|
|
|
|
#import <libpag/libpag.h>
|
|
|
|
|
#import <NIMSDK/NIMSDK.h>
|
2025-01-16 16:00:12 +08:00
|
|
|
|
#import <UIImageView+WebCache.h>
|
2025-01-15 19:02:58 +08:00
|
|
|
|
|
|
|
|
|
#import "UIView+VAP.h"
|
|
|
|
|
|
|
|
|
|
#import "ClientConfig.h"
|
|
|
|
|
#import "XPGiftStorage.h"
|
|
|
|
|
#import "UserInfoModel.h"
|
|
|
|
|
#import "RoomInfoModel.h"
|
|
|
|
|
#import "MicroQueueModel.h"
|
|
|
|
|
#import "AttachmentModel.h"
|
|
|
|
|
#import "QGVAPConfigModel.h"
|
|
|
|
|
#import "ActivityInfoModel.h"
|
|
|
|
|
#import "GiftReceiveInfoModel.h"
|
|
|
|
|
#import "XPRoomEnterHideTipView.h"
|
|
|
|
|
#import "XPMessageRemoteExtModel.h"
|
|
|
|
|
#import "PIBaseAnimationViewModel.h"
|
|
|
|
|
#import "XPRoomGiftAnimationParser.h"
|
|
|
|
|
|
|
|
|
|
#import "GiftComboManager.h"
|
|
|
|
|
#import "GiftAnimationManager.h"
|
|
|
|
|
|
|
|
|
|
#import "MSRoomGameWebVC.h"
|
|
|
|
|
#import "XPRoomViewController.h"
|
|
|
|
|
#import "PIUniversalBannerView.h"
|
|
|
|
|
#import "PIUniversalBannerModel.h"
|
|
|
|
|
|
|
|
|
|
#import "CPGiftBanner.h"
|
|
|
|
|
#import "CPLevelUpAnimation.h"
|
|
|
|
|
#import "CPBindingAnimation.h"
|
|
|
|
|
#import "GameUniversalBannerView.h"
|
|
|
|
|
#import "LuckyGiftWinningFlagView.h"
|
|
|
|
|
#import "LuckyGiftWinningBannerView.h"
|
|
|
|
|
#import "RoomHighValueGiftBannerAnimation.h"
|
2025-02-28 19:04:09 +08:00
|
|
|
|
#import "LuckyPackageBannerView.h"
|
2025-04-21 13:52:13 +08:00
|
|
|
|
#import "BravoGiftBannerView.h"
|
2025-01-16 16:00:12 +08:00
|
|
|
|
#import "XCCurrentVCStackManager.h"
|
2025-04-21 13:52:13 +08:00
|
|
|
|
#import "BravoGiftWinningFlagView.h"
|
2025-02-28 19:04:09 +08:00
|
|
|
|
#import "RoomEnterModel.h"
|
|
|
|
|
|
2025-01-16 16:00:12 +08:00
|
|
|
|
// Old Methods
|
|
|
|
|
#import "DatingInfoModel.h"
|
|
|
|
|
#import "XPWebViewController.h"
|
|
|
|
|
#import "XPRoomCandyGiftView.h"
|
|
|
|
|
#import "XPSailingAnimationView.h"
|
|
|
|
|
#import "AcrossRoomPKPrizeModel.h"
|
|
|
|
|
#import "XPRoomNobleLevelUpView.h"
|
2025-08-12 13:53:12 +08:00
|
|
|
|
|
2025-01-16 16:00:12 +08:00
|
|
|
|
#import "XPRoomGiftCompoundView.h"
|
|
|
|
|
#import "XPRoomGiftBroadcastView.h"
|
|
|
|
|
#import "XPRoomLuckyBigPrizeView.h"
|
|
|
|
|
#import "XPTreasureFairyGiftView.h"
|
|
|
|
|
#import "XPAcrossRoomPKPrizeView.h"
|
|
|
|
|
#import "PIRoomGiftBroadcastWindow.h"
|
|
|
|
|
#import "XPRoomDatingAnimationView.h"
|
|
|
|
|
#import "XPRoomAnchorRankBannerView.h"
|
2025-08-12 14:07:38 +08:00
|
|
|
|
|
2025-01-16 16:00:12 +08:00
|
|
|
|
#import "XPRoomGraffitiGiftAnimationView.h"
|
2025-08-12 17:44:32 +08:00
|
|
|
|
#import "XPRoomFunctionContainerView.h"
|
|
|
|
|
#import "XPRoomRankEntranceView.h"
|
|
|
|
|
#import "XPRoomAnchorRankEnterView.h"
|
2025-08-12 18:50:36 +08:00
|
|
|
|
#import "MSRoomOnLineView.h"
|
2025-01-16 16:00:12 +08:00
|
|
|
|
|
2025-01-15 19:02:58 +08:00
|
|
|
|
static const CGFloat kTipViewStayDuration = 3.0;
|
|
|
|
|
static const CGFloat kTipViewMoveDuration = 0.5;
|
|
|
|
|
|
|
|
|
|
@interface RoomAnimationView () <
|
|
|
|
|
PAGViewListener,
|
|
|
|
|
SVGAPlayerDelegate,
|
|
|
|
|
HWDMP4PlayDelegate,
|
|
|
|
|
GiftAnimationDelegate,
|
2025-01-16 16:00:12 +08:00
|
|
|
|
NIMBroadcastManagerDelegate,
|
|
|
|
|
|
|
|
|
|
PIUniversalBannerViewDelegate,
|
|
|
|
|
XPRoomGiftBroadcastViewDelegate,
|
|
|
|
|
XPRoomLuckyBigPrizeViewDelegate,
|
|
|
|
|
PIRoomGiftBroadcastWindowDelegate,
|
|
|
|
|
XPRoomAnchorRankBannerViewDelegate,
|
2025-08-12 14:07:38 +08:00
|
|
|
|
|
2025-08-15 19:34:25 +08:00
|
|
|
|
XPRoomGraffitiGiftAnimationViewDelegate,
|
|
|
|
|
UIGestureRecognizerDelegate
|
2025-01-15 19:02:58 +08:00
|
|
|
|
>
|
|
|
|
|
|
|
|
|
|
@property (nonatomic, weak) id<RoomHostDelegate>hostDelegate;
|
|
|
|
|
|
|
|
|
|
///最底层
|
|
|
|
|
@property (nonatomic, strong) XPRoomAnimationHitView *bottomContainer;
|
|
|
|
|
///中层
|
|
|
|
|
@property (nonatomic, strong) XPRoomAnimationHitView *middleContainer;
|
|
|
|
|
///顶层
|
|
|
|
|
@property (nonatomic, strong) XPRoomAnimationHitView *topContainer;
|
|
|
|
|
|
|
|
|
|
@property (nonatomic, strong) XPRoomAnimationHitView *bannerContainer;
|
2025-08-15 19:34:25 +08:00
|
|
|
|
@property (nonatomic, strong) UIView *bannerSwipeGestureContainer;
|
|
|
|
|
@property (nonatomic, strong) UIView *bannerLeftTapGestureContainer;
|
|
|
|
|
@property (nonatomic, strong) UIView *bannerRightTapGestureContainer;
|
2025-01-15 19:02:58 +08:00
|
|
|
|
|
|
|
|
|
/// --- 进场
|
2025-06-09 15:52:34 +08:00
|
|
|
|
/// 存放进房待播放动画的"队列"(这里用数组模拟队列 FIFO)
|
2025-01-15 19:02:58 +08:00
|
|
|
|
@property (nonatomic, strong) NSMutableArray<NSDictionary *> *enterRoomAnimationQueue;
|
|
|
|
|
/// 标记当前是否有进房动画在执行
|
|
|
|
|
@property (nonatomic, assign) BOOL isEnterRoomAnimating;
|
|
|
|
|
@property (nonatomic, strong) SVGAImageView *enterEffectView;
|
|
|
|
|
|
|
|
|
|
/// --- 礼物
|
|
|
|
|
@property(nonatomic, strong) PAGView *pagGiftEffectView;
|
|
|
|
|
@property(nonatomic, strong) SVGAParser *vggParser;
|
|
|
|
|
@property(nonatomic, assign) BOOL isPlayingGiftEffect;
|
|
|
|
|
@property(nonatomic, strong) NSMutableArray *svgaQueue;
|
|
|
|
|
@property(nonatomic, strong) VAPView *vapGiftEffectView;
|
2025-01-16 16:00:12 +08:00
|
|
|
|
@property(nonatomic, strong) SVGAImageView *vggGiftEffectView;
|
2025-01-15 19:02:58 +08:00
|
|
|
|
@property(nonatomic, strong) NSMutableArray *mp4AvatarLoaders;
|
|
|
|
|
@property(nonatomic, copy) NSString *GiftDynamicEffectListPath;
|
|
|
|
|
@property(nonatomic, strong) dispatch_source_t giftEffectTimer;
|
|
|
|
|
@property(nonatomic, strong) dispatch_queue_t giftEffectsQueue;
|
|
|
|
|
@property(nonatomic, strong) XPRoomGiftAnimationParser *vapParser;
|
|
|
|
|
@property(nonatomic, strong) GiftAnimationManager *giftAnimationManager;
|
|
|
|
|
@property(nonatomic, strong) GiftReceiveInfoModel *mp4TempReceiveInfoModel;
|
|
|
|
|
|
|
|
|
|
/// --- 飘屏
|
|
|
|
|
@property (nonatomic, strong) NSMutableArray *roomBannertModelsQueueV2; // 特效播放队列,包括幸运礼物 banner, CP banner 和 CP 特效
|
|
|
|
|
@property (nonatomic, assign) BOOL isRoomBannerV2Displaying;
|
|
|
|
|
|
2025-04-02 11:04:07 +08:00
|
|
|
|
// --- Brove 金币动画
|
|
|
|
|
@property (nonatomic, strong) SVGAVideoEntity *broveSVGAEntity_lv_1;
|
|
|
|
|
@property (nonatomic, strong) SVGAVideoEntity *broveSVGAEntity_lv_2;
|
|
|
|
|
@property (nonatomic, strong) SVGAVideoEntity *broveSVGAEntity_lv_3;
|
|
|
|
|
@property (nonatomic, strong) NSMutableArray *broveSVGAQueue;
|
|
|
|
|
@property (nonatomic, assign) BOOL isBroveSVGAPlaying;
|
|
|
|
|
@property (nonatomic, assign) NSInteger viewIndex;
|
|
|
|
|
|
2025-01-15 19:02:58 +08:00
|
|
|
|
/// --- 座驾
|
|
|
|
|
///座驾pag动效
|
|
|
|
|
@property(nonatomic, strong) PAGView *carPagEffectView;
|
|
|
|
|
///座驾VAP特效
|
|
|
|
|
@property(nonatomic, strong) VAPView *carVapEffectView;
|
|
|
|
|
@property(nonatomic, strong) SVGAImageView *carSVGAEffectView;
|
|
|
|
|
@property(nonatomic, strong) NSMutableArray<NSDictionary *> *carEffectQueue;
|
|
|
|
|
|
2025-01-16 16:00:12 +08:00
|
|
|
|
/// --- 旧逻辑,有需要再重构
|
|
|
|
|
@property(nonatomic, assign) BOOL isPlayOfB;
|
|
|
|
|
@property(nonatomic, strong) NSMutableArray<PIBaseAnimationViewModel *> *animationListB; // 玩法
|
|
|
|
|
@property(nonatomic, assign) CGFloat broadCastHieght;
|
|
|
|
|
@property (nonatomic, strong) NetImageView *imageLoader;
|
|
|
|
|
@property (nonatomic, strong) SVGAImageView *datingEffectView;
|
|
|
|
|
@property (nonatomic, strong) NSMutableArray<AttachmentModel *> *sailingQueue;
|
|
|
|
|
@property (nonatomic, strong) NSMutableArray<DatingInfoModel *> *datingEffectQueue;
|
|
|
|
|
@property (nonatomic, strong) NSMutableArray<AttachmentModel *> *graffitiGiftQueue;
|
|
|
|
|
@property (nonatomic, strong) NSMutableArray<AcrossRoomPKPrizeModel *> *acrossRoomPKQueue;
|
|
|
|
|
@property (nonatomic,strong) SVGAImageView *luckyGiftEffectView; ///福袋礼物送礼物的特效
|
|
|
|
|
@property (nonatomic, strong) VAPView *luckyVapGiftEffectView; ///福袋礼物VAP特效
|
|
|
|
|
|
2025-03-24 16:09:48 +08:00
|
|
|
|
@property(nonatomic, strong) NSMutableArray <PIUniversalBannerView *>* universalBannerViewCaches;
|
2025-08-15 19:34:25 +08:00
|
|
|
|
|
|
|
|
|
// Banner 手势相关属性
|
|
|
|
|
@property(nonatomic, assign) CGPoint savedTapPoint;
|
|
|
|
|
@property(nonatomic, assign) BOOL hasSavedTapPoint;
|
2025-01-15 19:02:58 +08:00
|
|
|
|
@end
|
|
|
|
|
|
2025-01-14 14:29:14 +08:00
|
|
|
|
@implementation RoomAnimationView
|
|
|
|
|
|
2025-02-28 19:04:09 +08:00
|
|
|
|
- (void)setIsPlayOfB:(BOOL)isPlayOfB {
|
|
|
|
|
_isPlayOfB = isPlayOfB;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-15 19:02:58 +08:00
|
|
|
|
- (void)dealloc
|
|
|
|
|
{
|
2025-01-22 21:22:58 +08:00
|
|
|
|
[[NIMSDK sharedSDK].broadcastManager removeDelegate:self];
|
|
|
|
|
|
|
|
|
|
[NSObject cancelPreviousPerformRequestsWithTarget:self];
|
|
|
|
|
|
|
|
|
|
[self pop_removeAllAnimations];
|
|
|
|
|
|
2025-03-24 16:09:48 +08:00
|
|
|
|
if (_giftEffectTimer && !dispatch_source_testcancel(_giftEffectTimer)) {
|
|
|
|
|
dispatch_source_cancel(_giftEffectTimer);
|
|
|
|
|
_giftEffectTimer = nil;
|
2025-01-15 19:02:58 +08:00
|
|
|
|
}
|
2025-03-24 16:09:48 +08:00
|
|
|
|
|
2025-01-22 21:22:58 +08:00
|
|
|
|
if (_giftEffectsQueue) {
|
2025-01-15 19:02:58 +08:00
|
|
|
|
self.giftEffectsQueue = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
-(void)resumeTimer{
|
|
|
|
|
if(self.giftEffectTimer != nil){
|
|
|
|
|
dispatch_source_cancel(self.giftEffectTimer);
|
|
|
|
|
self.giftEffectTimer = nil;
|
|
|
|
|
}
|
|
|
|
|
[self.pagGiftEffectView removeListener:self];
|
|
|
|
|
self.hostDelegate = nil;
|
|
|
|
|
[[GiftComboManager sharedManager] removeComboFlag];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (instancetype)initWithHostDelegate:(id<RoomHostDelegate>)hDelegate {
|
|
|
|
|
if (self = [super init]) {
|
|
|
|
|
self.hostDelegate = hDelegate;
|
|
|
|
|
[[NIMSDK sharedSDK].broadcastManager addDelegate:self];
|
|
|
|
|
|
2025-08-15 11:41:45 +08:00
|
|
|
|
// 确保RoomAnimationView可以接收用户交互
|
|
|
|
|
self.userInteractionEnabled = YES;
|
|
|
|
|
|
2025-01-15 19:02:58 +08:00
|
|
|
|
[self setup];
|
|
|
|
|
}
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma mark - SETUP
|
|
|
|
|
- (void)setup {
|
|
|
|
|
[self setupUI];
|
|
|
|
|
[self setupEnterRoom];
|
|
|
|
|
[self setupGiftEffects];
|
|
|
|
|
[self setupBanner];
|
|
|
|
|
[self setupCar];
|
2025-01-16 16:00:12 +08:00
|
|
|
|
[self setupOldMethods];
|
2025-08-15 19:34:25 +08:00
|
|
|
|
|
|
|
|
|
[self addBnnerContainGesture];
|
2025-01-15 19:02:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)setupUI {
|
|
|
|
|
[self addSubview:self.bottomContainer];
|
|
|
|
|
[self insertSubview:self.middleContainer aboveSubview:self.bottomContainer];
|
|
|
|
|
[self insertSubview:self.topContainer aboveSubview:self.middleContainer];
|
|
|
|
|
[self insertSubview:self.bannerContainer aboveSubview:self.topContainer];
|
|
|
|
|
|
|
|
|
|
[self.bottomContainer mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
|
|
make.edges.mas_equalTo(self);
|
|
|
|
|
}];
|
|
|
|
|
[self.middleContainer mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
|
|
make.edges.mas_equalTo(self);
|
|
|
|
|
}];
|
|
|
|
|
[self.topContainer mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
|
|
make.edges.mas_equalTo(self);
|
|
|
|
|
}];
|
|
|
|
|
[self.bannerContainer mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
|
|
make.top.mas_equalTo(self).offset(kNavigationHeight);
|
|
|
|
|
make.leading.trailing.mas_equalTo(self);
|
2025-08-12 17:44:32 +08:00
|
|
|
|
make.height.mas_equalTo(80);
|
2025-01-15 19:02:58 +08:00
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)setupEnterRoom {
|
|
|
|
|
self.enterRoomAnimationQueue = [NSMutableArray array];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)setupGiftEffects {
|
|
|
|
|
self.GiftDynamicEffectListPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) xpSafeObjectAtIndex:0] stringByAppendingPathComponent:@"GiftDynamicEffectList"];
|
|
|
|
|
|
|
|
|
|
self.giftAnimationManager = [[GiftAnimationManager alloc] initWithContainerView:self.bottomContainer];
|
|
|
|
|
self.giftAnimationManager.delegate = self;
|
|
|
|
|
|
|
|
|
|
_giftEffectsQueue = dispatch_queue_create("com.RoomGiftEffects.queue", DISPATCH_QUEUE_SERIAL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)setupBanner {
|
|
|
|
|
_roomBannertModelsQueueV2 = [NSMutableArray array];
|
2025-08-12 17:44:32 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#pragma mark - Legacy Support
|
|
|
|
|
|
2025-01-15 19:02:58 +08:00
|
|
|
|
- (void)setupCar {
|
|
|
|
|
_carEffectQueue = [NSMutableArray array];
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-16 16:00:12 +08:00
|
|
|
|
- (void)setupOldMethods {
|
|
|
|
|
_broadCastHieght = 190 - 150 + kGetScaleWidth(69);
|
|
|
|
|
_sailingQueue = @[].mutableCopy;
|
|
|
|
|
_datingEffectQueue = @[].mutableCopy;
|
|
|
|
|
_graffitiGiftQueue = @[].mutableCopy;
|
|
|
|
|
_acrossRoomPKQueue = @[].mutableCopy;
|
|
|
|
|
_animationListB = @[].mutableCopy;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-15 19:02:58 +08:00
|
|
|
|
#pragma mark - Method: Enter Roooooom
|
|
|
|
|
- (void)enterRoom:(NIMMessage *)message content:(NIMChatroomNotificationContent *)content {
|
|
|
|
|
NIMMessageChatroomExtension *messageExt = (NIMMessageChatroomExtension *)message.messageExt;
|
|
|
|
|
NSDictionary * dic = [(NSDictionary *)messageExt.roomExt.toJSONObject objectForKey:message.from];
|
|
|
|
|
XPMessageRemoteExtModel *extModel = [XPMessageRemoteExtModel modelWithJSON:dic];
|
|
|
|
|
|
2025-01-22 21:22:58 +08:00
|
|
|
|
if (extModel.platformRole == 1) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-15 19:02:58 +08:00
|
|
|
|
if (extModel.enterHide) {
|
|
|
|
|
//隐身进房
|
|
|
|
|
if ([message.from isEqualToString:[AccountInfoStorage instance].getUid]) {
|
|
|
|
|
[self createEnterHideAnimation];
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
[self userEnterRoom:content ext:extModel];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///自己的隐身进房提示
|
|
|
|
|
- (void)createEnterHideAnimation {
|
|
|
|
|
NSDictionary * dic= @{@"title":@"隐身进房",
|
2025-06-16 17:30:20 +08:00
|
|
|
|
@"isMe":@"",
|
2025-01-15 19:02:58 +08:00
|
|
|
|
@"experLevelSeq":@"",
|
|
|
|
|
@"effectPath" : @""};
|
|
|
|
|
[self.enterRoomAnimationQueue addObject:dic];
|
|
|
|
|
[self tryDequeueAnimation];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- (void)userEnterRoom:(NIMChatroomNotificationContent *)content ext:(XPMessageRemoteExtModel *)extModel {
|
|
|
|
|
NSString *userName = [self _resolveUserNameFromContent:content extModel:extModel];
|
|
|
|
|
NSString *title = [NSString stringWithFormat:YMLocalizedString(@"XPRoomAnimationView0"), userName];
|
|
|
|
|
|
|
|
|
|
NSDictionary * dic= @{@"title":title,
|
|
|
|
|
@"experLevelSeq":[NSString stringWithFormat:@"%ld", extModel.experLevelSeq],
|
|
|
|
|
@"effectPath" : extModel.enterRoomEffects.length ? extModel.enterRoomEffects : @""};
|
|
|
|
|
[self.enterRoomAnimationQueue addObject:dic];
|
|
|
|
|
[self tryDequeueAnimation];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)tryDequeueAnimation {
|
|
|
|
|
// 如果当前正有动画在播放,或者队列里啥都没有,直接return
|
|
|
|
|
if (self.isEnterRoomAnimating || self.enterRoomAnimationQueue.count == 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
self.isEnterRoomAnimating = YES;
|
|
|
|
|
|
|
|
|
|
// 取出队列头部的动画信息并移除
|
|
|
|
|
NSDictionary *dic = [self.enterRoomAnimationQueue firstObject];
|
2025-06-16 17:30:20 +08:00
|
|
|
|
if (self.enterRoomAnimationQueue.count > 0) {
|
|
|
|
|
[self.enterRoomAnimationQueue xpSafeRemoveObjectAtIndex:0];
|
|
|
|
|
}
|
2025-01-15 19:02:58 +08:00
|
|
|
|
|
|
|
|
|
NSString *title = [dic objectForKey:@"title"];
|
|
|
|
|
if ([title isEqualToString:@"隐身进房"]) {
|
|
|
|
|
[self playHideEnterRoomAnimation];
|
|
|
|
|
} else {
|
|
|
|
|
// 开始执行动画
|
|
|
|
|
[self playUserEnterRoomAnimation:[dic objectForKey:@"title"]
|
|
|
|
|
experLevelSeq:[dic objectForKey:@"experLevelSeq"]
|
2025-02-28 19:04:09 +08:00
|
|
|
|
effectPath:[dic objectForKey:@"effectPath"]
|
|
|
|
|
isCPEnter:[[dic objectForKey:@"isCP"] boolValue]];
|
2025-01-15 19:02:58 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)playHideEnterRoomAnimation {
|
|
|
|
|
XPRoomEnterHideTipView *enterHideTipView = [[XPRoomEnterHideTipView alloc] initWithFrame:CGRectMake(KScreenWidth,
|
|
|
|
|
(KScreenHeight - 48) * 0.5,
|
|
|
|
|
KScreenWidth,
|
|
|
|
|
48)];
|
|
|
|
|
[self.bottomContainer addSubview:enterHideTipView];
|
|
|
|
|
|
|
|
|
|
@kWeakify(self);
|
|
|
|
|
[self enterRoomAnimationFor:enterHideTipView
|
|
|
|
|
startFrom:enterHideTipView.center
|
|
|
|
|
startTo:CGPointMake(enterHideTipView.frame.size.width / 2, enterHideTipView.center.y)
|
|
|
|
|
endFrom:CGPointMake(0, enterHideTipView.center.y)
|
|
|
|
|
endTo:CGPointMake(-KScreenWidth / 2, enterHideTipView.center.y)
|
|
|
|
|
duration:CACurrentMediaTime() + kTipViewStayDuration
|
|
|
|
|
completion:^(BOOL finished) {
|
|
|
|
|
@kStrongify(self);
|
|
|
|
|
[self endAnimationEnterEffect];
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)playUserEnterRoomAnimation:(NSString *)title
|
|
|
|
|
experLevelSeq:(NSString *)experLevelSeq
|
2025-02-28 19:04:09 +08:00
|
|
|
|
effectPath:(NSString *)effectPath
|
|
|
|
|
isCPEnter:(BOOL)isCP {
|
2025-01-15 19:02:58 +08:00
|
|
|
|
|
|
|
|
|
NSDictionary *attributes = @{
|
|
|
|
|
NSFontAttributeName:kFontRegular(26),
|
|
|
|
|
NSForegroundColorAttributeName:[UIColor whiteColor]
|
|
|
|
|
};
|
|
|
|
|
NSMutableAttributedString *attributeString = [[NSMutableAttributedString alloc] initWithString:title
|
|
|
|
|
attributes:attributes];
|
|
|
|
|
[attributeString setYy_alignment:NSTextAlignmentLeft];
|
|
|
|
|
|
|
|
|
|
BOOL hasEffectPath = ![NSString isEmpty:effectPath];
|
|
|
|
|
[self addEnterEffectView: hasEffectPath];
|
|
|
|
|
|
2025-02-28 19:04:09 +08:00
|
|
|
|
if (isCP) {
|
|
|
|
|
[self playCPPPPEnterRoomSvgaWith:attributeString];
|
|
|
|
|
} else if (hasEffectPath) {
|
2025-01-15 19:02:58 +08:00
|
|
|
|
[self playEnterRoomSvga:effectPath
|
|
|
|
|
content:attributeString
|
|
|
|
|
needMoveAnimation:YES];
|
|
|
|
|
} else {
|
|
|
|
|
[self playEnterRoomSvgaWith:experLevelSeq
|
|
|
|
|
content:attributeString];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)addEnterEffectView:(BOOL)hasEffectPath {
|
|
|
|
|
if (self.enterEffectView.superview == nil) {
|
|
|
|
|
[self.bottomContainer addSubview:self.enterEffectView];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self.enterEffectView.loops = hasEffectPath ? 0 : 1;
|
|
|
|
|
|
|
|
|
|
self.enterEffectView.frame = CGRectMake(hasEffectPath ? KScreenWidth : 0,
|
|
|
|
|
340 + kSafeAreaTopHeight,
|
|
|
|
|
KScreenWidth,
|
|
|
|
|
hasEffectPath ? 75 : 50);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)playEnterRoomSvga:(NSString *)path
|
|
|
|
|
content:(NSAttributedString *)content
|
|
|
|
|
needMoveAnimation:(BOOL)isNeed {
|
|
|
|
|
@kWeakify(self);
|
|
|
|
|
SVGAParser *parser = [[SVGAParser alloc] init];
|
|
|
|
|
[parser parseWithURL:[NSURL URLWithString:path]
|
|
|
|
|
completionBlock:^(SVGAVideoEntity * _Nullable videoItem) {
|
|
|
|
|
@kStrongify(self);
|
|
|
|
|
self.enterEffectView.alpha = 1;
|
2025-02-28 19:04:09 +08:00
|
|
|
|
self.enterEffectView.hidden = NO;
|
2025-01-15 19:02:58 +08:00
|
|
|
|
self.enterEffectView.videoItem = videoItem;
|
|
|
|
|
[self.enterEffectView setAttributedText:content forKey:@"room_text"];
|
|
|
|
|
[self.enterEffectView startAnimation];
|
|
|
|
|
if (isNeed) {
|
|
|
|
|
[self popAnimationEnterEffect];
|
|
|
|
|
}
|
|
|
|
|
} failureBlock:^(NSError * _Nullable error) {
|
|
|
|
|
@kStrongify(self);
|
|
|
|
|
[self endAnimationEnterEffect];
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)playEnterRoomSvgaWith:(NSString *)seq
|
|
|
|
|
content:(NSAttributedString *)content {
|
|
|
|
|
NSInteger seqNum = [NSString isEmpty:seq] ? 0 : [seq integerValue];
|
|
|
|
|
NSString *path = [self _mapExperLevelSeqToLocalKey:seqNum];
|
|
|
|
|
if ([NSString isEmpty:path]) {
|
|
|
|
|
[self endAnimationEnterEffect];
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NSString *targetPath = [NSString stringWithFormat:@"%@/%@.svga", @"https://image.molistar.xyz", path];
|
|
|
|
|
[self playEnterRoomSvga:targetPath content:content needMoveAnimation:NO];
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-28 19:04:09 +08:00
|
|
|
|
- (void)playCPPPPEnterRoomSvgaWith:(NSAttributedString *)content {
|
|
|
|
|
if ([NSString isEmpty:content.string]) {
|
|
|
|
|
[self endAnimationEnterEffect];
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
NSString *path = @"CP进场";
|
|
|
|
|
@kWeakify(self);
|
|
|
|
|
SVGAParser *parser = [[SVGAParser alloc] init];
|
|
|
|
|
[parser parseWithNamed:path inBundle:[NSBundle mainBundle] completionBlock:^(SVGAVideoEntity * _Nonnull videoItem) {
|
|
|
|
|
@kStrongify(self);
|
|
|
|
|
self.enterEffectView.loops = 0;
|
|
|
|
|
self.enterEffectView.alpha = 1;
|
|
|
|
|
self.enterEffectView.hidden = NO;
|
|
|
|
|
self.enterEffectView.videoItem = videoItem;
|
|
|
|
|
[self.enterEffectView setAttributedText:content forKey:@"room_text"];
|
|
|
|
|
[self.enterEffectView startAnimation];
|
|
|
|
|
[self popAnimationEnterEffect];
|
|
|
|
|
} failureBlock:^(NSError * _Nonnull error) {
|
|
|
|
|
@kStrongify(self);
|
|
|
|
|
[self endAnimationEnterEffect];
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-15 19:02:58 +08:00
|
|
|
|
- (void)popAnimationEnterEffect {
|
|
|
|
|
@kWeakify(self);
|
|
|
|
|
[self enterRoomAnimationFor:self.enterEffectView
|
|
|
|
|
startFrom:self.enterEffectView.center
|
|
|
|
|
startTo:CGPointMake(self.enterEffectView.frame.size.width / 2, self.enterEffectView.center.y)
|
|
|
|
|
endFrom:CGPointMake(0, self.enterEffectView.center.y)
|
|
|
|
|
endTo:CGPointMake(-KScreenWidth / 2, self.enterEffectView.center.y)
|
|
|
|
|
duration:CACurrentMediaTime() + kTipViewStayDuration
|
|
|
|
|
completion:^(BOOL finished) {
|
|
|
|
|
@kStrongify(self);
|
|
|
|
|
[self endAnimationEnterEffect];
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)endAnimationEnterEffect {
|
|
|
|
|
self.isEnterRoomAnimating = NO;
|
2025-01-22 21:22:58 +08:00
|
|
|
|
[self.enterEffectView stopAnimation];
|
|
|
|
|
self.enterEffectView.hidden = YES;
|
|
|
|
|
[self.enterEffectView removeFromSuperview];
|
2025-01-15 19:02:58 +08:00
|
|
|
|
[self tryDequeueAnimation];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma mark - Method: Banner
|
2025-08-13 18:16:46 +08:00
|
|
|
|
- (void)inserBannerModelToQueue:(AttachmentModel *)obj {
|
|
|
|
|
// 参数验证
|
|
|
|
|
if (!obj || ![obj isKindOfClass:[AttachmentModel class]]) {
|
|
|
|
|
NSLog(@"⚠️ 警告: inserBannerModelToQueue 接收到无效参数: %@", obj);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-15 19:34:25 +08:00
|
|
|
|
#if DEBUG
|
2025-08-13 18:16:46 +08:00
|
|
|
|
// DEBUG环境:复制banner数据用于测试
|
2025-08-15 19:34:25 +08:00
|
|
|
|
BOOL enableBannerCopy = obj.second == Custom_Message_Sub_Super_Gift_Banner;// YES; // 设置为NO可以禁用复制功能
|
2025-08-13 18:16:46 +08:00
|
|
|
|
NSInteger copyCount = 10; // 可以调整这个数字来改变复制数量
|
|
|
|
|
|
2025-08-15 19:34:25 +08:00
|
|
|
|
if (enableBannerCopy) {
|
|
|
|
|
NSLog(@"🧪 DEBUG环境:收到banner数据,复制%ld份用于测试", (long)copyCount);
|
|
|
|
|
NSLog(@"🧪 原始banner类型: %@", NSStringFromClass([obj class]));
|
2025-08-13 18:16:46 +08:00
|
|
|
|
|
|
|
|
|
// 添加原始数据
|
2025-08-15 19:34:25 +08:00
|
|
|
|
[self.roomBannertModelsQueueV2 addObject:obj];
|
2025-08-13 18:16:46 +08:00
|
|
|
|
|
|
|
|
|
// 复制指定份数
|
|
|
|
|
for (int i = 1; i < copyCount; i++) {
|
|
|
|
|
AttachmentModel *copiedObj = [[AttachmentModel alloc] init];
|
|
|
|
|
|
|
|
|
|
// 安全复制data
|
|
|
|
|
if ([obj.data respondsToSelector:@selector(mutableCopy)]) {
|
|
|
|
|
copiedObj.data = [obj.data mutableCopy];
|
|
|
|
|
} else if ([obj.data respondsToSelector:@selector(copy)]) {
|
|
|
|
|
copiedObj.data = [obj.data copy];
|
|
|
|
|
} else {
|
|
|
|
|
copiedObj.data = obj.data; // 直接引用,注意这可能不是深拷贝
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
copiedObj.first = obj.first;
|
|
|
|
|
copiedObj.second = obj.second;
|
|
|
|
|
copiedObj.isBroadcast = obj.isBroadcast;
|
|
|
|
|
copiedObj.seq = obj.seq;
|
|
|
|
|
|
|
|
|
|
NSLog(@"🧪 复制第%d份banner数据", i + 1);
|
|
|
|
|
[self.roomBannertModelsQueueV2 addObject:copiedObj];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NSLog(@"🧪 队列中banner总数: %ld", (long)self.roomBannertModelsQueueV2.count);
|
|
|
|
|
|
|
|
|
|
// 显示队列中banner类型的分布
|
|
|
|
|
NSMutableDictionary *typeCount = [NSMutableDictionary dictionary];
|
|
|
|
|
for (AttachmentModel *banner in self.roomBannertModelsQueueV2) {
|
|
|
|
|
NSString *typeKey = [NSString stringWithFormat:@"%d", banner.second];
|
|
|
|
|
NSNumber *count = typeCount[typeKey];
|
|
|
|
|
typeCount[typeKey] = @(count.integerValue + 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NSLog(@"🧪 队列中banner类型分布:");
|
|
|
|
|
for (NSString *typeKey in typeCount.allKeys) {
|
|
|
|
|
NSLog(@" - 类型%@: %@个", typeKey, typeCount[typeKey]);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// 禁用复制功能,正常添加
|
|
|
|
|
NSLog(@"🧪 DEBUG环境:复制功能已禁用,正常添加banner");
|
|
|
|
|
[self.roomBannertModelsQueueV2 addObject:obj];
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
// 生产环境:正常添加
|
2025-03-24 16:09:48 +08:00
|
|
|
|
[self.roomBannertModelsQueueV2 addObject:obj];
|
2025-08-13 18:16:46 +08:00
|
|
|
|
#endif
|
|
|
|
|
|
2025-03-24 16:09:48 +08:00
|
|
|
|
if (!self.isRoomBannerV2Displaying) {
|
|
|
|
|
[self processNextRoomEffectAttachment];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)sortBannerQueue {
|
|
|
|
|
RoomInfoModel *roomInfo = self.hostDelegate.getRoomInfo;
|
|
|
|
|
NSString *currentRoomUid = @(roomInfo.uid).stringValue;
|
|
|
|
|
NSString *currentUid = [AccountInfoStorage instance].getUid;
|
|
|
|
|
[self.roomBannertModelsQueueV2 sortUsingComparator:^NSComparisonResult(AttachmentModel * _Nonnull obj1, AttachmentModel * _Nonnull obj2) {
|
|
|
|
|
|
|
|
|
|
// 检查 obj1 的属性
|
|
|
|
|
NSArray *obj1UidList = [obj1.data valueForKey:@"uidList"];
|
2025-03-25 15:22:01 +08:00
|
|
|
|
NSNumber *obj1RoomUid = [obj1.data valueForKey:@"roomUid"];
|
2025-03-24 16:09:48 +08:00
|
|
|
|
BOOL obj1IsCurrentUser = obj1UidList && [obj1UidList containsObject:currentUid];
|
2025-03-25 15:22:01 +08:00
|
|
|
|
BOOL obj1IsCurrentRoom = obj1RoomUid && [obj1RoomUid.stringValue isEqualToString:currentRoomUid];
|
2025-03-24 16:09:48 +08:00
|
|
|
|
|
|
|
|
|
// 检查 obj2 的属性
|
|
|
|
|
NSArray *obj2UidList = [obj2.data valueForKey:@"uidList"];
|
2025-03-25 15:22:01 +08:00
|
|
|
|
NSNumber *obj2RoomUid = [obj2.data valueForKey:@"roomUid"];
|
2025-03-24 16:09:48 +08:00
|
|
|
|
BOOL obj2IsCurrentUser = obj2UidList && [obj2UidList containsObject:currentUid];
|
2025-03-25 15:22:01 +08:00
|
|
|
|
BOOL obj2IsCurrentRoom = obj2RoomUid && [obj2RoomUid.stringValue isEqualToString:currentRoomUid];
|
2025-03-24 16:09:48 +08:00
|
|
|
|
|
|
|
|
|
if (obj1IsCurrentUser && !obj2IsCurrentUser) {
|
|
|
|
|
return NSOrderedAscending;
|
|
|
|
|
} else if (!obj1IsCurrentUser && obj2IsCurrentUser) {
|
|
|
|
|
return NSOrderedDescending;
|
|
|
|
|
} else if (obj1IsCurrentRoom && !obj2IsCurrentRoom) {
|
|
|
|
|
return NSOrderedAscending;
|
|
|
|
|
} else if (!obj1IsCurrentRoom && obj2IsCurrentRoom) {
|
|
|
|
|
return NSOrderedDescending;
|
|
|
|
|
} else {
|
|
|
|
|
return NSOrderedSame;
|
|
|
|
|
}
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-15 19:02:58 +08:00
|
|
|
|
- (void)processNextRoomEffectAttachment {
|
2025-08-13 18:16:46 +08:00
|
|
|
|
NSLog(@"🔄 processNextRoomEffectAttachment 被调用 - 当前状态: isRoomBannerV2Displaying=%@, 队列数量: %ld",
|
|
|
|
|
self.isRoomBannerV2Displaying ? @"YES" : @"NO", (long)self.roomBannertModelsQueueV2.count);
|
|
|
|
|
|
2025-01-15 19:02:58 +08:00
|
|
|
|
// 检查队列是否有元素
|
|
|
|
|
if (self.roomBannertModelsQueueV2.count == 0) {
|
|
|
|
|
// 如果队列为空,停止处理
|
|
|
|
|
self.isRoomBannerV2Displaying = NO;
|
2025-08-13 18:16:46 +08:00
|
|
|
|
NSLog(@"🔄 队列为空,停止处理");
|
2025-01-15 19:02:58 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
2025-02-28 19:04:09 +08:00
|
|
|
|
if (self.isRoomBannerV2Displaying) {
|
2025-08-13 18:16:46 +08:00
|
|
|
|
NSLog(@"🔄 已有banner正在显示,跳过处理");
|
2025-02-28 19:04:09 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
2025-03-24 16:09:48 +08:00
|
|
|
|
|
|
|
|
|
[self sortBannerQueue];
|
2025-01-15 19:02:58 +08:00
|
|
|
|
|
|
|
|
|
// 从队列中取出第一个元素并移出队列
|
|
|
|
|
AttachmentModel *nextAttachment = [self.roomBannertModelsQueueV2 firstObject];
|
2025-06-16 17:30:20 +08:00
|
|
|
|
if (self.roomBannertModelsQueueV2.count > 0) {
|
|
|
|
|
[self.roomBannertModelsQueueV2 xpSafeRemoveObjectAtIndex:0];
|
|
|
|
|
}
|
2025-01-15 19:02:58 +08:00
|
|
|
|
|
|
|
|
|
// 设置为正在显示的状态
|
|
|
|
|
self.isRoomBannerV2Displaying = YES;
|
2025-08-13 18:16:46 +08:00
|
|
|
|
NSLog(@"🔄 设置状态为正在显示: %@", NSStringFromClass([nextAttachment class]));
|
|
|
|
|
|
|
|
|
|
// 清理之前的banner,防止多个banner同时显示(保留debug视图)
|
|
|
|
|
NSMutableArray *viewsToRemove = [NSMutableArray array];
|
|
|
|
|
for (UIView *subview in self.bannerContainer.subviews) {
|
2025-08-15 19:34:25 +08:00
|
|
|
|
[viewsToRemove addObject:subview];
|
|
|
|
|
NSLog(@"🔄 标记移除banner: %@", NSStringFromClass([subview class]));
|
2025-08-13 18:16:46 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (UIView *view in viewsToRemove) {
|
|
|
|
|
[view removeFromSuperview];
|
|
|
|
|
}
|
2025-01-15 19:02:58 +08:00
|
|
|
|
|
|
|
|
|
switch (nextAttachment.second) {
|
|
|
|
|
case Custom_Message_Sub_General_Floating_Screen_One_Room:
|
|
|
|
|
case Custom_Message_Sub_General_Floating_Screen_All_Room:
|
|
|
|
|
// 通用飘屏
|
|
|
|
|
[self playGameBanner:nextAttachment];
|
|
|
|
|
break;
|
|
|
|
|
case Custom_Message_Sub_Super_Gift_Winning_Coins_ALL_Room:
|
|
|
|
|
[self playLuckyWinningBanner:nextAttachment];
|
|
|
|
|
break;
|
|
|
|
|
case Custom_Message_Sub_CP_Gift:
|
|
|
|
|
[self playCPGiftBanner:nextAttachment];
|
|
|
|
|
break;
|
|
|
|
|
case Custom_Message_Sub_CP_Upgrade:
|
|
|
|
|
[self playCPLevelUp:nextAttachment];
|
|
|
|
|
break;
|
|
|
|
|
case Custom_Message_Sub_CP_Binding:
|
|
|
|
|
[self playCPBinding:nextAttachment];
|
|
|
|
|
break;
|
|
|
|
|
case Custom_Message_Sub_Gift_ChannelNotify:
|
|
|
|
|
[self playRoomGiftBanner:nextAttachment];
|
|
|
|
|
break;
|
2025-02-28 19:04:09 +08:00
|
|
|
|
case Custom_Message_Sub_LuckyPackage:
|
|
|
|
|
[self playLuckyPackageBanner:nextAttachment];
|
|
|
|
|
break;
|
2025-04-02 11:04:07 +08:00
|
|
|
|
case Custom_Message_Sub_Super_Gift_Banner:
|
|
|
|
|
[self playBroveBanner:nextAttachment];
|
|
|
|
|
break;
|
2025-01-15 19:02:58 +08:00
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-02 11:04:07 +08:00
|
|
|
|
- (void)playBroveBanner:(AttachmentModel *)obj {
|
|
|
|
|
if (!obj.data) {
|
|
|
|
|
self.isRoomBannerV2Displaying = NO;
|
|
|
|
|
[self processNextRoomEffectAttachment];
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
self.isRoomBannerV2Displaying = YES;
|
|
|
|
|
@kWeakify(self);
|
2025-04-10 18:01:01 +08:00
|
|
|
|
RoomInfoModel *roomInfo = self.hostDelegate.getRoomInfo;
|
2025-04-21 13:52:13 +08:00
|
|
|
|
[BravoGiftBannerView display:self.bannerContainer
|
2025-04-10 18:01:01 +08:00
|
|
|
|
inRoomUid:roomInfo.uid
|
2025-04-02 11:04:07 +08:00
|
|
|
|
with:obj
|
|
|
|
|
complete:^{
|
|
|
|
|
@kStrongify(self);
|
2025-08-13 18:16:46 +08:00
|
|
|
|
NSLog(@"🔄 BravoGiftBannerView complete 回调被调用");
|
2025-04-02 11:04:07 +08:00
|
|
|
|
self.isRoomBannerV2Displaying = NO;
|
|
|
|
|
[self processNextRoomEffectAttachment];
|
2025-04-10 18:01:01 +08:00
|
|
|
|
} exitCurrentRoom:^{
|
|
|
|
|
@kStrongify(self);
|
|
|
|
|
[self.hostDelegate exitRoom];
|
2025-04-02 11:04:07 +08:00
|
|
|
|
}];
|
|
|
|
|
}
|
2025-02-28 19:04:09 +08:00
|
|
|
|
|
|
|
|
|
- (void)playLuckyPackageBanner:(AttachmentModel *)obj {
|
|
|
|
|
if (!obj.data) {
|
|
|
|
|
self.isRoomBannerV2Displaying = NO;
|
|
|
|
|
[self processNextRoomEffectAttachment];
|
|
|
|
|
return;
|
|
|
|
|
}
|
2025-04-02 11:04:07 +08:00
|
|
|
|
self.isRoomBannerV2Displaying = YES;
|
2025-02-28 19:04:09 +08:00
|
|
|
|
@kWeakify(self);
|
|
|
|
|
RoomInfoModel *roomInfo = self.hostDelegate.getRoomInfo;
|
|
|
|
|
[LuckyPackageBannerView display:self.bannerContainer
|
|
|
|
|
inRoomUid:roomInfo.uid
|
|
|
|
|
with:obj
|
|
|
|
|
complete:^{
|
|
|
|
|
@kStrongify(self);
|
2025-08-13 18:16:46 +08:00
|
|
|
|
NSLog(@"🔄 LuckyPackageBannerView complete 回调被调用");
|
2025-02-28 19:04:09 +08:00
|
|
|
|
self.isRoomBannerV2Displaying = NO;
|
|
|
|
|
[self processNextRoomEffectAttachment];
|
|
|
|
|
} exitCurrentRoom:^{
|
|
|
|
|
@kStrongify(self);
|
|
|
|
|
[self.hostDelegate exitRoom];
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-15 19:02:58 +08:00
|
|
|
|
- (void)receiveRoomGiftBanner:(AttachmentModel *)obj {
|
2025-03-24 16:09:48 +08:00
|
|
|
|
[self inserBannerModelToQueue:obj];
|
2025-01-15 19:02:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)playRoomGiftBanner:(AttachmentModel *)obj {
|
2025-01-22 21:22:58 +08:00
|
|
|
|
if (!obj.data) {
|
2025-02-28 19:04:09 +08:00
|
|
|
|
self.isRoomBannerV2Displaying = NO;
|
2025-01-22 21:22:58 +08:00
|
|
|
|
[self processNextRoomEffectAttachment];
|
|
|
|
|
return;
|
|
|
|
|
}
|
2025-04-02 11:04:07 +08:00
|
|
|
|
self.isRoomBannerV2Displaying = YES;
|
2025-01-15 19:02:58 +08:00
|
|
|
|
@kWeakify(self);
|
|
|
|
|
[RoomHighValueGiftBannerAnimation display:self.bannerContainer
|
|
|
|
|
with:obj
|
|
|
|
|
complete:^{
|
|
|
|
|
@kStrongify(self);
|
2025-08-13 18:16:46 +08:00
|
|
|
|
NSLog(@"🔄 RoomHighValueGiftBannerAnimation complete 回调被调用");
|
2025-02-28 19:04:09 +08:00
|
|
|
|
self.isRoomBannerV2Displaying = NO;
|
2025-01-15 19:02:58 +08:00
|
|
|
|
[self processNextRoomEffectAttachment];
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)receiveCPEvent:(AttachmentModel *)attachment {
|
2025-03-24 16:09:48 +08:00
|
|
|
|
[self inserBannerModelToQueue:attachment];
|
2025-01-15 19:02:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)playCPBinding:(AttachmentModel *)attachment {
|
|
|
|
|
@kWeakify(self);
|
|
|
|
|
[CPBindingAnimation display:self.topContainer
|
|
|
|
|
with:attachment
|
|
|
|
|
complete:^{
|
|
|
|
|
@kStrongify(self);
|
2025-02-28 19:04:09 +08:00
|
|
|
|
self.isRoomBannerV2Displaying = NO;
|
2025-01-15 19:02:58 +08:00
|
|
|
|
[self processNextRoomEffectAttachment];
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)playCPGiftBanner:(AttachmentModel *)attachMent {
|
|
|
|
|
@kWeakify(self);
|
|
|
|
|
[CPGiftBanner display:self.bannerContainer
|
|
|
|
|
with:attachMent
|
|
|
|
|
complete:^{
|
|
|
|
|
@kStrongify(self);
|
2025-08-13 18:16:46 +08:00
|
|
|
|
NSLog(@"🔄 CPGiftBanner complete 回调被调用");
|
2025-02-28 19:04:09 +08:00
|
|
|
|
self.isRoomBannerV2Displaying = NO;
|
2025-01-15 19:02:58 +08:00
|
|
|
|
[self processNextRoomEffectAttachment];
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)playCPLevelUp:(AttachmentModel *)attachMent {
|
|
|
|
|
@kWeakify(self);
|
|
|
|
|
[CPLevelUpAnimation display:self.topContainer
|
|
|
|
|
with:attachMent
|
|
|
|
|
complete:^{
|
|
|
|
|
@kStrongify(self);
|
2025-02-28 19:04:09 +08:00
|
|
|
|
self.isRoomBannerV2Displaying = NO;
|
2025-01-15 19:02:58 +08:00
|
|
|
|
[self processNextRoomEffectAttachment];
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)receiveLuckGiftWinning:(AttachmentModel *)attachment {
|
|
|
|
|
RoomInfoModel *roomInfo = self.hostDelegate.getRoomInfo;
|
|
|
|
|
[LuckyGiftWinningFlagView display:self.topContainer
|
|
|
|
|
with:attachment
|
|
|
|
|
roomID:roomInfo.roomId
|
|
|
|
|
uID:[AccountInfoStorage instance].getUid];
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-21 13:52:13 +08:00
|
|
|
|
- (void)receiveBravoGiftWinning:(AttachmentModel *)attachment {
|
2025-04-02 11:04:07 +08:00
|
|
|
|
RoomInfoModel *roomInfo = self.hostDelegate.getRoomInfo;
|
2025-04-21 13:52:13 +08:00
|
|
|
|
BravoGiftWinningFlagViewModel *flagModel = [BravoGiftWinningFlagView display:self.topContainer
|
2025-08-15 19:34:25 +08:00
|
|
|
|
with:attachment
|
|
|
|
|
roomID:roomInfo.roomId
|
|
|
|
|
uID:[AccountInfoStorage instance].getUid];
|
2025-04-02 11:04:07 +08:00
|
|
|
|
if (flagModel.roomId != roomInfo.roomId || flagModel.uid != [AccountInfoStorage instance].getUid.integerValue) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2025-04-25 15:54:30 +08:00
|
|
|
|
if ([flagModel.receiverUidList containsObject:@([AccountInfoStorage instance].getUid.integerValue)]) {
|
|
|
|
|
// 数据同步到 combo
|
|
|
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:@"receiveLuckGiftWinning" object:[NSString stringByRemovingRedundantZeros:@(flagModel.receiverProfit).stringValue]];
|
|
|
|
|
}
|
2025-04-21 13:52:13 +08:00
|
|
|
|
|
2025-04-02 11:04:07 +08:00
|
|
|
|
if (!self.hostDelegate.getRoomInfo.hasAnimationEffect) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
NSDictionary *tip = [attachment.data objectForKey:@"tip"];
|
|
|
|
|
if (tip) {
|
|
|
|
|
NSNumber *level = [tip objectForKey:@"level"];
|
|
|
|
|
NSNumber *coins = [tip objectForKey:@"coins"];
|
|
|
|
|
if (level) {
|
|
|
|
|
[self loadBroveSVGAVideoItem:level.integerValue];
|
|
|
|
|
}
|
|
|
|
|
if (coins) {
|
2025-04-25 15:54:30 +08:00
|
|
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:@"receiveLuckGiftWinning" object:[NSString stringByRemovingRedundantZeros:coins.stringValue]];
|
2025-04-02 11:04:07 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)loadBroveSVGAVideoItem:(NSInteger)level {
|
2025-04-10 18:01:01 +08:00
|
|
|
|
if (level < 3) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2025-04-02 11:04:07 +08:00
|
|
|
|
NSString *svgaItemName = @"";
|
|
|
|
|
SVGAVideoEntity *entity;
|
2025-08-15 19:34:25 +08:00
|
|
|
|
svgaItemName = @"大";
|
|
|
|
|
entity = self.broveSVGAEntity_lv_3;
|
|
|
|
|
/*
|
2025-04-02 11:04:07 +08:00
|
|
|
|
switch (level) {
|
2025-08-15 19:34:25 +08:00
|
|
|
|
case 1:
|
|
|
|
|
svgaItemName = @"小";
|
|
|
|
|
entity = self.broveSVGAEntity_lv_1;
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
svgaItemName = @"中";
|
|
|
|
|
entity = self.broveSVGAEntity_lv_2;
|
|
|
|
|
break;
|
2025-04-02 11:04:07 +08:00
|
|
|
|
case 3:
|
|
|
|
|
svgaItemName = @"大";
|
|
|
|
|
entity = self.broveSVGAEntity_lv_3;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
2025-08-15 19:34:25 +08:00
|
|
|
|
*/
|
2025-04-02 11:04:07 +08:00
|
|
|
|
if ([NSString isEmpty:svgaItemName]) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (self.broveSVGAQueue.count >=3) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SVGAImageView *svgaView = [[SVGAImageView alloc] initWithFrame:CGRectMake(0, 0, KScreenWidth, KScreenHeight)];
|
|
|
|
|
svgaView.backgroundColor = [UIColor clearColor];
|
|
|
|
|
svgaView.contentMode = UIViewContentModeScaleAspectFill;
|
|
|
|
|
svgaView.userInteractionEnabled = NO;
|
|
|
|
|
if (!entity) {
|
|
|
|
|
@kWeakify(self);
|
|
|
|
|
SVGAParser *parser = [[SVGAParser alloc] init];
|
|
|
|
|
[parser parseWithNamed:svgaItemName
|
|
|
|
|
inBundle:[NSBundle mainBundle]
|
|
|
|
|
completionBlock:^(SVGAVideoEntity * _Nonnull videoItem) {
|
|
|
|
|
@kStrongify(self);
|
2025-08-15 19:34:25 +08:00
|
|
|
|
self.broveSVGAEntity_lv_3 = videoItem;
|
|
|
|
|
/*
|
2025-04-02 11:04:07 +08:00
|
|
|
|
switch (level) {
|
2025-08-15 19:34:25 +08:00
|
|
|
|
case 1:
|
|
|
|
|
self.broveSVGAEntity_lv_1 = videoItem;
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
self.broveSVGAEntity_lv_2 = videoItem;
|
|
|
|
|
break;
|
2025-04-02 11:04:07 +08:00
|
|
|
|
case 3:
|
|
|
|
|
self.broveSVGAEntity_lv_3 = videoItem;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
2025-08-15 19:34:25 +08:00
|
|
|
|
*/
|
2025-04-02 11:04:07 +08:00
|
|
|
|
[self startPlayBroveSVGA:svgaView level:level];
|
|
|
|
|
} failureBlock:^(NSError * _Nonnull error) {
|
|
|
|
|
|
|
|
|
|
}];
|
|
|
|
|
} else {
|
|
|
|
|
[self startPlayBroveSVGA:svgaView level:level];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)startPlayBroveSVGA:(SVGAImageView *)svgaView level:(NSInteger)level {
|
|
|
|
|
if (!_broveSVGAQueue) {
|
|
|
|
|
_broveSVGAQueue = [[NSMutableArray alloc] init];
|
|
|
|
|
self.viewIndex = 0;
|
|
|
|
|
}
|
|
|
|
|
if (![self.broveSVGAQueue containsObject:svgaView]) {
|
|
|
|
|
[self.broveSVGAQueue addObject:svgaView];
|
|
|
|
|
}
|
|
|
|
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)((0.3 + (self.viewIndex * 0.1)) * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
|
|
|
|
SVGAVideoEntity *entity;
|
|
|
|
|
switch (level) {
|
|
|
|
|
case 1:
|
|
|
|
|
entity = self.broveSVGAEntity_lv_1;
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
entity = self.broveSVGAEntity_lv_2;
|
|
|
|
|
break;
|
|
|
|
|
case 3:
|
|
|
|
|
entity = self.broveSVGAEntity_lv_3;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
// [self insertSubview:svgaView atIndex:self.viewIndex];
|
|
|
|
|
[self _addSubviewToMiddleContainer:svgaView];
|
|
|
|
|
svgaView.tag = 913;
|
|
|
|
|
svgaView.delegate = self;
|
|
|
|
|
svgaView.videoItem = entity;
|
|
|
|
|
svgaView.loops = 1;
|
|
|
|
|
[svgaView startAnimation];
|
|
|
|
|
self.viewIndex += 1;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-15 19:02:58 +08:00
|
|
|
|
- (void)receiveLuckGiftBanner:(AttachmentModel *)attachment {
|
2025-03-24 16:09:48 +08:00
|
|
|
|
[self inserBannerModelToQueue:attachment];
|
2025-01-15 19:02:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)playLuckyWinningBanner:(AttachmentModel *)nextAttachment {
|
|
|
|
|
RoomInfoModel *roomInfo = self.hostDelegate.getRoomInfo;
|
|
|
|
|
@kWeakify(self);
|
|
|
|
|
[LuckyGiftWinningBannerView display:self.bannerContainer
|
|
|
|
|
inRoomUid:roomInfo.uid
|
|
|
|
|
with:nextAttachment
|
|
|
|
|
complete:^{
|
|
|
|
|
@kStrongify(self);
|
2025-08-13 18:16:46 +08:00
|
|
|
|
NSLog(@"🔄 LuckyGiftWinningBannerView complete 回调被调用");
|
2025-02-28 19:04:09 +08:00
|
|
|
|
self.isRoomBannerV2Displaying = NO;
|
2025-01-15 19:02:58 +08:00
|
|
|
|
[self processNextRoomEffectAttachment];
|
|
|
|
|
} exitCurrentRoom:^{
|
|
|
|
|
@kStrongify(self);
|
|
|
|
|
[self.hostDelegate exitRoom];
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
-(void)receiveRoomGeneralFloatingScreen:(AttachmentModel *)attachment{
|
|
|
|
|
PIBaseAnimationViewModel *roomGraffiti = [PIBaseAnimationViewModel new];
|
|
|
|
|
roomGraffiti.data = attachment.data;
|
|
|
|
|
roomGraffiti.type = GiftBannerType_General_Floating_Screen;
|
|
|
|
|
roomGraffiti.first = attachment.first;
|
|
|
|
|
roomGraffiti.second = attachment.second;
|
|
|
|
|
|
|
|
|
|
PIUniversalBannerModel *model = [PIUniversalBannerModel modelWithDictionary:attachment.data];
|
|
|
|
|
if (model.skipType == 7 &&
|
|
|
|
|
(attachment.second == Custom_Message_Sub_General_Floating_Screen_One_Room ||
|
|
|
|
|
attachment.second == Custom_Message_Sub_General_Floating_Screen_All_Room)) {
|
|
|
|
|
[self receiveGameBanner:attachment];
|
|
|
|
|
} else {
|
2025-01-16 16:00:12 +08:00
|
|
|
|
if(self.animationListB.count == 0 && self.isPlayOfB == NO){
|
|
|
|
|
[self createGeneralFloatingScreenAnimation:roomGraffiti bannerModel:model];
|
|
|
|
|
}
|
|
|
|
|
[self.animationListB addObject:roomGraffiti];
|
2025-01-15 19:02:58 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)receiveGameBanner:(AttachmentModel *)attachment {
|
2025-03-24 16:09:48 +08:00
|
|
|
|
[self inserBannerModelToQueue:attachment];
|
2025-01-15 19:02:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)playGameBanner:(AttachmentModel *)attachment {
|
|
|
|
|
@kWeakify(self);
|
|
|
|
|
[GameUniversalBannerView display:self.bannerContainer
|
|
|
|
|
with:attachment
|
|
|
|
|
complete:^{
|
|
|
|
|
@kStrongify(self);
|
2025-08-13 18:16:46 +08:00
|
|
|
|
NSLog(@"🔄 GameUniversalBannerView complete 回调被调用");
|
2025-02-28 19:04:09 +08:00
|
|
|
|
self.isRoomBannerV2Displaying = NO;
|
2025-01-15 19:02:58 +08:00
|
|
|
|
[self processNextRoomEffectAttachment];
|
|
|
|
|
} goToGame:^(NSInteger gameID) {
|
|
|
|
|
@kStrongify(self);
|
|
|
|
|
NSArray *baishunList = [self.hostDelegate getPlayList];
|
|
|
|
|
for (ActivityInfoModel *model in baishunList) {
|
|
|
|
|
if (model.id == gameID) {
|
|
|
|
|
MSRoomGameWebVC *vc = [[MSRoomGameWebVC alloc]initWithDelegate:self.hostDelegate
|
|
|
|
|
gameModel:model];
|
|
|
|
|
vc.view.frame = CGRectMake(0, 0, KScreenWidth, KScreenHeight);
|
|
|
|
|
XPRoomViewController *roomVC = (XPRoomViewController *)self.hostDelegate;
|
|
|
|
|
[roomVC addChildViewController:vc];
|
2025-01-22 21:22:58 +08:00
|
|
|
|
RoomAnimationView *animationView;
|
2025-01-15 19:02:58 +08:00
|
|
|
|
for (id obj in self.hostDelegate.getSuperView.subviews) {
|
2025-01-22 21:22:58 +08:00
|
|
|
|
if ([obj isKindOfClass:[RoomAnimationView class]]){
|
2025-01-15 19:02:58 +08:00
|
|
|
|
animationView = obj;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
[self.hostDelegate.getSuperView addSubview:vc.view];
|
|
|
|
|
vc.view.tag = 913;
|
2025-02-28 19:04:09 +08:00
|
|
|
|
break;
|
2025-01-15 19:02:58 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma mark - Method: Car
|
|
|
|
|
- (void)handleCarEnter:(AttachmentModel *)attachment {
|
|
|
|
|
if (attachment.second == Custom_Message_Sub_Car_EnterRoom) {
|
|
|
|
|
if (self.isPlayingGiftEffect) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if ([self _isInSudGame]) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!self.hostDelegate.getRoomInfo.hasAnimationEffect) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2025-01-22 21:22:58 +08:00
|
|
|
|
if (self.hostDelegate.getUserInfo.platformRole == 1) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2025-01-15 19:02:58 +08:00
|
|
|
|
NSInteger otherViewType = [attachment.data[@"otherViewType"] integerValue];
|
|
|
|
|
NSString *viewUrl = attachment.data[@"viewUrl"];
|
|
|
|
|
NSString *effect = attachment.data[@"effect"];
|
|
|
|
|
NSDictionary *dic = nil;
|
|
|
|
|
if (![NSString isEmpty:viewUrl]) {
|
|
|
|
|
dic = @{@"otherViewType":@(otherViewType), @"viewUrl":viewUrl};
|
|
|
|
|
} else if(![NSString isEmpty:effect]) {
|
|
|
|
|
dic = @{@"effect":effect};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[self starHandleCarEffect:dic];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)starHandleCarEffect:(NSDictionary *)dic {
|
|
|
|
|
if (!dic) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
[self.carEffectQueue addObject:dic];
|
|
|
|
|
[self playCarEffect:dic];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)nextCarEffect {
|
|
|
|
|
if (self.carEffectQueue.count > 0) {
|
2025-06-16 17:30:20 +08:00
|
|
|
|
if (self.carEffectQueue.count > 0) {
|
|
|
|
|
[self.carEffectQueue xpSafeRemoveObjectAtIndex:0];
|
|
|
|
|
}
|
2025-01-15 19:02:58 +08:00
|
|
|
|
}
|
|
|
|
|
if (self.carEffectQueue.count > 0) {
|
|
|
|
|
[self playCarEffect:self.carEffectQueue.firstObject];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)playCarEffect:(NSDictionary *)effectDict {
|
|
|
|
|
NSString *viewUrl = [effectDict objectForKey:@"viewUrl"];
|
|
|
|
|
NSString *carEffect = [effectDict objectForKey:@"effect"];
|
|
|
|
|
@kWeakify(self);
|
|
|
|
|
if (![NSString isEmpty:viewUrl]) {
|
|
|
|
|
[self.vapParser parseWithURL:viewUrl completionBlock:^(NSString * _Nullable videoUrl) {
|
|
|
|
|
@kStrongify(self);
|
|
|
|
|
if (![NSString isEmpty:videoUrl]) {
|
|
|
|
|
if([videoUrl.lowercaseString containsString:@".pag"]){
|
|
|
|
|
self.carPagEffectView.hidden = NO;
|
|
|
|
|
[self _addSubviewToMiddleContainer:self.carPagEffectView];
|
|
|
|
|
[self.carPagEffectView setPath:videoUrl];
|
|
|
|
|
[self.carPagEffectView play];
|
|
|
|
|
} else {
|
|
|
|
|
self.carVapEffectView.hidden = NO;
|
|
|
|
|
[self _addSubviewToMiddleContainer:self.carVapEffectView];
|
|
|
|
|
[self.carVapEffectView setMute:NO];
|
|
|
|
|
[self.carVapEffectView playHWDMP4:videoUrl repeatCount:1 delegate:self];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} failureBlock:^(NSError * _Nullable error) {
|
|
|
|
|
@kStrongify(self);
|
|
|
|
|
[self nextCarEffect];
|
|
|
|
|
}];
|
|
|
|
|
} else if (![NSString isEmpty:carEffect]) {
|
|
|
|
|
[self.vggParser parseWithURL:[NSURL URLWithString:carEffect]
|
|
|
|
|
completionBlock:^(SVGAVideoEntity * _Nullable videoItem) {
|
|
|
|
|
@kStrongify(self);
|
|
|
|
|
if (videoItem) {
|
|
|
|
|
[self _addSubviewToMiddleContainer:self.carSVGAEffectView];
|
|
|
|
|
[self _updateGiftEffectContentMode:self.carSVGAEffectView
|
|
|
|
|
size:videoItem.videoSize];
|
|
|
|
|
self.carSVGAEffectView.videoItem = videoItem;
|
|
|
|
|
[self.carSVGAEffectView startAnimation];
|
|
|
|
|
}
|
|
|
|
|
} failureBlock:^(NSError * _Nullable error) {
|
|
|
|
|
@kStrongify(self);
|
|
|
|
|
[self nextCarEffect];
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma mark - Method: Send Gifts
|
|
|
|
|
- (void)receiveGiftHandleSendGiftAnimationWith:(GiftReceiveInfoModel *)receiveInfo attachment:(AttachmentModel *)attachment {
|
|
|
|
|
if (!self.hostDelegate.getRoomInfo.hasAnimationEffect) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GiftInfoModel *giftInfo = receiveInfo.gift;
|
|
|
|
|
if (attachment.second == Custom_Message_Sub_AllMicroLuckySend ||
|
|
|
|
|
attachment.second == Custom_Message_Sub_AllBatchMicroLuckySend ||
|
|
|
|
|
attachment.second == Custom_Message_Sub_Gift_LuckySend) {
|
|
|
|
|
NSString * giftId = [NSString stringWithFormat:@"%ld", receiveInfo.luckyGiftList.giftList.firstObject.giftId];
|
2025-04-21 13:52:13 +08:00
|
|
|
|
NSString *roomUid = receiveInfo.roomUid == 0 ? receiveInfo.uid : @(receiveInfo.roomUid).stringValue;
|
|
|
|
|
giftInfo = [[XPGiftStorage shareStorage] findGiftInfo:giftId inRoom:roomUid];
|
2025-01-15 19:02:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (giftInfo == nil) {
|
2025-03-06 15:26:44 +08:00
|
|
|
|
giftInfo = [[XPGiftStorage shareStorage] findGiftInfo:receiveInfo.giftId inRoom:@(receiveInfo.roomUid).stringValue];
|
2025-01-15 19:02:58 +08:00
|
|
|
|
}
|
2025-02-28 19:04:09 +08:00
|
|
|
|
if (giftInfo == nil) {
|
|
|
|
|
giftInfo = [receiveInfo.displayGift xpSafeObjectAtIndex:0];
|
|
|
|
|
}
|
2025-01-15 19:02:58 +08:00
|
|
|
|
|
|
|
|
|
receiveInfo.gift = giftInfo;
|
|
|
|
|
RoomInfoModel * roomInfo = [self.hostDelegate getRoomInfo];
|
|
|
|
|
if ((giftInfo.otherViewType == GiftOtherViewTypeMp4 ||
|
|
|
|
|
giftInfo.otherViewType == GiftOtherViewTypePag) &&
|
|
|
|
|
giftInfo.viewUrl.length > 0 && roomInfo.hasAnimationEffect) {
|
|
|
|
|
receiveInfo.mp4Url = giftInfo.viewUrl;
|
|
|
|
|
} else if (giftInfo.hasVggPic &&
|
|
|
|
|
giftInfo.vggUrl.length > 0
|
|
|
|
|
&& roomInfo.hasAnimationEffect) {///SVGA动画
|
|
|
|
|
receiveInfo.vggUrl = giftInfo.vggUrl;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-16 16:00:12 +08:00
|
|
|
|
if (attachment.second != Custom_Message_Sub_Gift_EmbeddedStyle) {
|
|
|
|
|
// Custom_Message_Sub_Gift_EmbeddedStyle 只需播放特效
|
|
|
|
|
[self.giftAnimationManager enqueueGift:receiveInfo];
|
|
|
|
|
}
|
2025-01-15 19:02:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)receiveGift:(GiftReceiveInfoModel *)receiveInfo {
|
|
|
|
|
if (receiveInfo.isHomeShow) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-16 16:00:12 +08:00
|
|
|
|
// 处理 combo
|
2025-01-15 19:02:58 +08:00
|
|
|
|
[[GiftComboManager sharedManager] receiveGiftInfoForDisplayComboFlags:receiveInfo
|
|
|
|
|
container:self];
|
|
|
|
|
|
|
|
|
|
if (receiveInfo.isLuckyBagGift) {
|
2025-01-16 16:00:12 +08:00
|
|
|
|
if (receiveInfo.isShowAnimation) {
|
|
|
|
|
[self handleLuckyBagGifts:receiveInfo];
|
|
|
|
|
}
|
2025-01-15 19:02:58 +08:00
|
|
|
|
} else {
|
|
|
|
|
if (![NSString isEmpty:receiveInfo.mp4Url] || ![NSString isEmpty:receiveInfo.vggUrl]) {
|
2025-03-24 16:09:48 +08:00
|
|
|
|
[self addToSvgaQueue:receiveInfo];
|
2025-01-15 19:02:58 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-06 16:45:34 +08:00
|
|
|
|
dispatch_async(self.giftEffectsQueue, ^{
|
|
|
|
|
if (self.giftEffectTimer == nil &&
|
|
|
|
|
self.svgaQueue.count > 0) {
|
|
|
|
|
[self startHandleGiftEffectTimer];
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2025-01-15 19:02:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-01-16 16:00:12 +08:00
|
|
|
|
- (void)handleLuckyBagGifts:(GiftReceiveInfoModel *)receiveInfo {
|
|
|
|
|
//如果是福袋礼物的话 就不用看他的价值了 只要有SVGA的话 就播放
|
|
|
|
|
// MARK: 此代码从 XPRoomAnimationView copy 而来,暂时无法确认其正确性
|
|
|
|
|
RoomInfoModel * roomInfo = [self.hostDelegate getRoomInfo];
|
|
|
|
|
if (receiveInfo.displayGift.count > 0) {
|
|
|
|
|
[receiveInfo.displayGift enumerateObjectsUsingBlock:^(GiftInfoModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
|
|
|
|
if ((obj.otherViewType == GiftOtherViewTypeMp4 || obj.otherViewType == GiftOtherViewTypePag) && obj.viewUrl && obj.viewUrl.length > 0 && roomInfo.hasAnimationEffect) {
|
|
|
|
|
GiftReceiveInfoModel * model = [[GiftReceiveInfoModel alloc] init];
|
|
|
|
|
model.mp4Url = obj.viewUrl;
|
|
|
|
|
model.avatar = receiveInfo.sendUserAvatar;
|
|
|
|
|
model.gift = obj;
|
|
|
|
|
model.giftNum = [obj.giftNum integerValue];;
|
|
|
|
|
model.nick = receiveInfo.nick;
|
|
|
|
|
model.targetUids = receiveInfo.targetUids;
|
|
|
|
|
model.isBatch = receiveInfo.isBatch;
|
|
|
|
|
model.targetAvatar = receiveInfo.targetAvatar;
|
|
|
|
|
model.targetNick = receiveInfo.targetNick;
|
2025-03-24 16:09:48 +08:00
|
|
|
|
[self addToSvgaQueue:model];
|
2025-01-16 16:00:12 +08:00
|
|
|
|
} else if (obj.hasVggPic && roomInfo.hasAnimationEffect) {
|
|
|
|
|
GiftReceiveInfoModel * model = [[GiftReceiveInfoModel alloc] init];
|
|
|
|
|
model.mp4Url = obj.viewUrl;
|
|
|
|
|
model.avatar = receiveInfo.sendUserAvatar;
|
|
|
|
|
model.gift = obj;
|
|
|
|
|
model.giftNum = [obj.giftNum integerValue];;
|
|
|
|
|
model.nick = receiveInfo.nick;
|
|
|
|
|
model.targetUids = receiveInfo.targetUids;
|
|
|
|
|
model.isBatch = receiveInfo.isBatch;
|
|
|
|
|
model.targetAvatar = receiveInfo.targetAvatar;
|
|
|
|
|
model.targetNick = receiveInfo.targetNick;
|
2025-03-24 16:09:48 +08:00
|
|
|
|
[self addToSvgaQueue:model];
|
2025-01-16 16:00:12 +08:00
|
|
|
|
}
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-15 19:02:58 +08:00
|
|
|
|
- (void)startHandleGiftEffectTimer {
|
|
|
|
|
NSTimeInterval period = 2.0;
|
|
|
|
|
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
|
|
|
|
|
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
|
|
|
|
|
dispatch_source_set_timer(timer, dispatch_walltime(NULL, 0), period * NSEC_PER_SEC, 0); //每秒执行
|
|
|
|
|
@kWeakify(self);
|
|
|
|
|
dispatch_source_set_event_handler(timer, ^{
|
|
|
|
|
@kStrongify(self)
|
|
|
|
|
if (!self) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
dispatch_async(self.giftEffectsQueue, ^{
|
2025-05-06 16:45:34 +08:00
|
|
|
|
NSLog(@"******************* 当前队列个数: %@,image loader 个数: %@", @(self.svgaQueue.count), @(self.mp4AvatarLoaders.count));
|
2025-01-15 19:02:58 +08:00
|
|
|
|
if (self.svgaQueue.count == 0) {
|
|
|
|
|
dispatch_source_cancel(timer);
|
|
|
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
|
|
self.giftEffectTimer = nil;
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
if (self.isPlayingGiftEffect == NO) {
|
|
|
|
|
self.isPlayingGiftEffect = YES;
|
|
|
|
|
GiftReceiveInfoModel *receiveModel = [self.svgaQueue xpSafeObjectAtIndex:0];
|
|
|
|
|
if ([receiveModel isKindOfClass:[GiftReceiveInfoModel class]]) {
|
|
|
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
|
|
[self createGiftSvgaAnimation:receiveModel];
|
|
|
|
|
});
|
|
|
|
|
}else {
|
2025-03-24 16:09:48 +08:00
|
|
|
|
[self removeFromSvgaQueueAtIndex:0];
|
2025-01-15 19:02:58 +08:00
|
|
|
|
self.isPlayingGiftEffect = NO;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
self.giftEffectTimer = timer;
|
|
|
|
|
dispatch_resume(timer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
-(void)createGiftSvgaAnimation:(GiftReceiveInfoModel *)receiveInfo {
|
|
|
|
|
GiftInfoModel *giftInfo = receiveInfo.gift;
|
|
|
|
|
NSString *targetURL = @"";
|
|
|
|
|
|
|
|
|
|
if (receiveInfo.isLuckyBagGift) {
|
|
|
|
|
// 播放背包礼物动画
|
|
|
|
|
if (![NSString isEmpty:receiveInfo.mp4Url]) {
|
|
|
|
|
[self stopCarEffect:giftInfo.goldPrice];
|
|
|
|
|
targetURL = receiveInfo.mp4Url;
|
2025-01-16 16:00:12 +08:00
|
|
|
|
[self playLuckyGiftEffectWithVapUrl:receiveInfo.mp4Url];
|
2025-01-15 19:02:58 +08:00
|
|
|
|
} else if (![NSString isEmpty:receiveInfo.luckyGiftSvgaUrl]) {
|
|
|
|
|
[self stopCarEffect:giftInfo.goldPrice];
|
|
|
|
|
targetURL = receiveInfo.luckyGiftSvgaUrl;
|
|
|
|
|
[self playGiftEffectWithVapUrl:receiveInfo.luckyGiftSvgaUrl];
|
|
|
|
|
} else if (![NSString isEmpty:giftInfo.luckyGiftSvgaUrl]) {
|
|
|
|
|
[self stopCarEffect:giftInfo.goldPrice];
|
|
|
|
|
targetURL = giftInfo.luckyGiftSvgaUrl;
|
|
|
|
|
[self playGiftEffectWithVapUrl:giftInfo.luckyGiftSvgaUrl];
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2025-02-28 19:04:09 +08:00
|
|
|
|
[self stopCarEffect:giftInfo.goldPrice];
|
2025-01-15 19:02:58 +08:00
|
|
|
|
if (giftInfo.otherViewType == GiftOtherViewTypePag ||
|
|
|
|
|
giftInfo.otherViewType == GiftOtherViewTypeMp4) {
|
2025-02-28 19:04:09 +08:00
|
|
|
|
if (giftInfo.otherViewType == GiftOtherViewTypePag) {
|
2025-01-15 19:02:58 +08:00
|
|
|
|
[self playGiftEffectWithPagUrl:giftInfo.viewUrl];
|
|
|
|
|
targetURL = giftInfo.viewUrl;
|
2025-02-28 19:04:09 +08:00
|
|
|
|
} else {
|
2025-01-15 19:02:58 +08:00
|
|
|
|
self.mp4TempReceiveInfoModel = receiveInfo;
|
|
|
|
|
[self playGiftEffectWithVapUrl:giftInfo.viewUrl];
|
|
|
|
|
targetURL = giftInfo.viewUrl;
|
2025-02-28 19:04:09 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 兜底,同时判断是否可以执行 svga
|
|
|
|
|
if ([NSString isEmpty:targetURL] && giftInfo.hasVggPic && giftInfo.vggUrl.length > 0) {
|
|
|
|
|
[self playGiftEffectWithVggUrl:giftInfo.vggUrl];
|
|
|
|
|
targetURL = giftInfo.vggUrl;
|
|
|
|
|
}
|
2025-01-15 19:02:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-04-02 11:04:07 +08:00
|
|
|
|
// NSLog(@"******************* 执行播放, 是否MP4:%@,URL: %@, self.svgaQueue num: %@", @(giftInfo.otherViewType), targetURL, @(self.svgaQueue.count));
|
2025-01-15 19:02:58 +08:00
|
|
|
|
|
|
|
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:@"kExchangeRoomAnimationViewAndGameViewIndex"
|
|
|
|
|
object:nil];
|
|
|
|
|
@kWeakify(self);
|
|
|
|
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.25 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
|
|
|
|
@kStrongify(self);
|
2025-03-24 16:09:48 +08:00
|
|
|
|
[self removeFromSvgaQueueAtIndex:0];
|
2025-01-15 19:02:58 +08:00
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)stopCarEffect:(double)goldPrice {
|
|
|
|
|
if ([ClientConfig shareConfig].configInfo.hideCarEffectGiftPrice <= goldPrice) {
|
|
|
|
|
[self.carEffectQueue removeAllObjects];
|
|
|
|
|
[self.carSVGAEffectView stopAnimation];
|
|
|
|
|
[self.carVapEffectView stopHWDMP4];
|
|
|
|
|
[self.carPagEffectView stop];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)playGiftEffectWithPagUrl:(NSString *)pagUrl {
|
|
|
|
|
@kWeakify(self);
|
|
|
|
|
[self.vapParser parseWithURL:pagUrl
|
|
|
|
|
completionBlock:^(NSString * _Nullable videoUrl) {
|
|
|
|
|
@kStrongify(self);
|
|
|
|
|
if ([NSString isEmpty:videoUrl]) {
|
|
|
|
|
[self playPAGFailure];
|
|
|
|
|
} else {
|
|
|
|
|
[self _addSubviewToMiddleContainer:self.pagGiftEffectView];
|
|
|
|
|
[self.pagGiftEffectView setPath:videoUrl];
|
|
|
|
|
[self.pagGiftEffectView play];
|
|
|
|
|
}
|
|
|
|
|
} failureBlock:^(NSError * _Nullable error) {
|
|
|
|
|
@kStrongify(self);
|
|
|
|
|
[self playPAGFailure];
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)playGiftEffectWithVapUrl:(NSString *)vapUrl {
|
|
|
|
|
NSString *encodingUrl = [vapUrl pureURLString];
|
|
|
|
|
NSString *fullPath = [self _findFullPath:vapUrl];
|
|
|
|
|
|
|
|
|
|
self.mp4AvatarLoaders = @[].mutableCopy;
|
|
|
|
|
if ([[NSFileManager defaultManager] fileExistsAtPath:fullPath]){
|
|
|
|
|
[self playVAG:fullPath];
|
|
|
|
|
}else {
|
|
|
|
|
@kWeakify(self);
|
|
|
|
|
[self.vapParser parseWithURL:encodingUrl
|
|
|
|
|
completionBlock:^(NSString * _Nullable videoUrl) {
|
|
|
|
|
@kStrongify(self);
|
|
|
|
|
if ([NSString isEmpty:videoUrl]) {
|
|
|
|
|
[self playVAGFailure];
|
|
|
|
|
} else {
|
|
|
|
|
[self playVAG:videoUrl];
|
|
|
|
|
}
|
|
|
|
|
} failureBlock:^(NSError * _Nullable error) {
|
|
|
|
|
@kStrongify(self);
|
|
|
|
|
[self playVAGFailure];
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)playGiftEffectWithVggUrl:(NSString *)vggUrl {
|
|
|
|
|
NSString *encodingUrl = [vggUrl pureURLString];
|
|
|
|
|
NSString *fullPath = [self _findFullPath:vggUrl];
|
2025-04-02 11:04:07 +08:00
|
|
|
|
// NSLog(@"******************* 解释 SVGA : %@ | %@", encodingUrl, fullPath);
|
2025-01-15 19:02:58 +08:00
|
|
|
|
if (![NSString isEmpty:fullPath] && [[NSFileManager defaultManager] fileExistsAtPath:fullPath]) {
|
|
|
|
|
NSData *data = [NSData dataWithContentsOfFile:fullPath options:0 error:NULL];
|
|
|
|
|
NSString *fileName = [[encodingUrl componentsSeparatedByString:@"/"] lastObject];
|
|
|
|
|
@kWeakify(self);
|
|
|
|
|
[self.vggParser parseWithData:data
|
|
|
|
|
cacheKey:fileName
|
|
|
|
|
completionBlock:^(SVGAVideoEntity * _Nonnull videoItem) {
|
|
|
|
|
@kStrongify(self);
|
|
|
|
|
if (videoItem) {
|
|
|
|
|
[self playVGG:videoItem];
|
|
|
|
|
} else {
|
|
|
|
|
[self playVGGFailure];
|
|
|
|
|
}
|
|
|
|
|
} failureBlock:^(NSError * _Nonnull error) {
|
|
|
|
|
@kStrongify(self);
|
|
|
|
|
[self playVGGFailure];
|
|
|
|
|
}];
|
|
|
|
|
} else {
|
|
|
|
|
@kWeakify(self);
|
|
|
|
|
[self.vggParser parseWithURL:[NSURL URLWithString:encodingUrl]
|
|
|
|
|
completionBlock:^(SVGAVideoEntity * _Nullable videoItem) {
|
|
|
|
|
@kStrongify(self);
|
2025-04-02 11:04:07 +08:00
|
|
|
|
// NSLog(@"******************* 解释 SVGA 成功");
|
2025-01-15 19:02:58 +08:00
|
|
|
|
if (videoItem) {
|
|
|
|
|
[self playVGG:videoItem];
|
|
|
|
|
} else {
|
|
|
|
|
[self playVGGFailure];
|
|
|
|
|
}
|
|
|
|
|
} failureBlock:^(NSError * _Nullable error) {
|
|
|
|
|
@kStrongify(self);
|
2025-04-02 11:04:07 +08:00
|
|
|
|
// NSLog(@"******************* 解释 SVGA 失败:%@", error);
|
2025-01-15 19:02:58 +08:00
|
|
|
|
[self playVGGFailure];
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)playVGG:(SVGAVideoEntity *)videoItem {
|
2025-02-28 19:04:09 +08:00
|
|
|
|
[self.vggGiftEffectView stopAnimation];
|
2025-01-15 19:02:58 +08:00
|
|
|
|
[self _addSubviewToMiddleContainer:self.vggGiftEffectView];
|
|
|
|
|
[self _updateGiftEffectContentMode:self.vggGiftEffectView
|
|
|
|
|
size:videoItem.videoSize];
|
|
|
|
|
self.vggGiftEffectView.videoItem = videoItem;
|
|
|
|
|
[self.vggGiftEffectView startAnimation];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)playVGGFailure {
|
|
|
|
|
[self playVGGEnd];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)playVGGEnd {
|
|
|
|
|
self.isPlayingGiftEffect = NO;
|
|
|
|
|
self.vggGiftEffectView.hidden = YES;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)playVAG:(NSString *)url {
|
|
|
|
|
@kWeakify(self);
|
|
|
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
|
|
@kStrongify(self);
|
|
|
|
|
[self _addSubviewToMiddleContainer:self.vapGiftEffectView];
|
|
|
|
|
[self.vapGiftEffectView setMute:NO];
|
|
|
|
|
[self.vapGiftEffectView playHWDMP4:url
|
|
|
|
|
repeatCount:1
|
|
|
|
|
delegate:self];
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)playVAGFailure {
|
|
|
|
|
[self playVAGEnd];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)playVAGEnd {
|
|
|
|
|
self.isPlayingGiftEffect = NO;
|
|
|
|
|
self.vapGiftEffectView.hidden = YES;
|
|
|
|
|
[self.vapGiftEffectView setMute:YES];
|
|
|
|
|
[self.vapGiftEffectView stopHWDMP4];
|
2025-03-24 16:09:48 +08:00
|
|
|
|
[self.vapGiftEffectView removeFromSuperview];
|
|
|
|
|
self.vapGiftEffectView = nil;
|
2025-01-15 19:02:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)playPAGFailure {
|
|
|
|
|
self.isPlayingGiftEffect = NO;
|
|
|
|
|
self.pagGiftEffectView.hidden = YES;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma mark - Delegates
|
|
|
|
|
#pragma mark - SVGA delegate
|
|
|
|
|
- (void)svgaPlayerDidFinishedAnimation:(SVGAPlayer *)player {
|
2025-04-02 11:04:07 +08:00
|
|
|
|
if (player.tag == 913) {
|
|
|
|
|
[player clear];
|
|
|
|
|
player.delegate = nil;
|
|
|
|
|
[player removeFromSuperview];
|
|
|
|
|
self.viewIndex -= 1;
|
|
|
|
|
if ([self.broveSVGAQueue containsObject:player]) {
|
|
|
|
|
[self.broveSVGAQueue removeObject:player];
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
2025-01-15 19:02:58 +08:00
|
|
|
|
if (player == self.enterEffectView && player.loops == 1) {
|
|
|
|
|
[self endAnimationEnterEffect];
|
|
|
|
|
}
|
|
|
|
|
else if (player == self.vggGiftEffectView) {
|
|
|
|
|
[self playVGGEnd];
|
|
|
|
|
}
|
|
|
|
|
else if (player == self.carSVGAEffectView) {
|
|
|
|
|
self.carSVGAEffectView.hidden = YES;
|
|
|
|
|
[self.carSVGAEffectView removeFromSuperview];
|
|
|
|
|
[self nextCarEffect];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma mark - HWDMP4PlayDelegate
|
|
|
|
|
- (BOOL)shouldStartPlayMP4:(VAPView *)container config:(QGVAPConfigModel *)config {
|
|
|
|
|
CGFloat width = config.info.size.width;
|
|
|
|
|
CGFloat height = config.info.size.height;
|
|
|
|
|
|
|
|
|
|
container.center = self.center;
|
|
|
|
|
[container mas_updateConstraints:^(MASConstraintMaker *make) {
|
|
|
|
|
make.width.mas_equalTo(KScreenWidth);
|
|
|
|
|
make.height.mas_equalTo(KScreenWidth * height / width);
|
|
|
|
|
}];
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)viewDidFinishPlayMP4:(NSInteger)totalFrameCount view:(VAPView *)container {
|
|
|
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
|
|
container.hidden = YES;
|
|
|
|
|
if (container == self.carVapEffectView) {
|
|
|
|
|
[self.carVapEffectView removeFromSuperview];
|
|
|
|
|
self.carVapEffectView = nil;
|
|
|
|
|
[self nextCarEffect];
|
|
|
|
|
}
|
|
|
|
|
else if (container == self.vapGiftEffectView) {
|
|
|
|
|
[self playVAGEnd];
|
|
|
|
|
}
|
2025-01-16 16:00:12 +08:00
|
|
|
|
else if(container == self.luckyVapGiftEffectView) {
|
|
|
|
|
[self.luckyVapGiftEffectView removeFromSuperview];
|
|
|
|
|
self.luckyVapGiftEffectView = nil;
|
|
|
|
|
}
|
2025-01-15 19:02:58 +08:00
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)viewDidStopPlayMP4:(NSInteger)lastFrameIndex view:(VAPView *)container {
|
|
|
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
|
|
container.hidden = YES;
|
|
|
|
|
if (container == self.carVapEffectView) {
|
|
|
|
|
[self.carVapEffectView removeFromSuperview];
|
|
|
|
|
[self nextCarEffect];
|
|
|
|
|
}
|
|
|
|
|
else if (container == self.vapGiftEffectView) {
|
|
|
|
|
[self playVAGEnd];
|
|
|
|
|
}
|
2025-01-16 16:00:12 +08:00
|
|
|
|
else if(container == self.luckyVapGiftEffectView) {
|
|
|
|
|
[self.luckyVapGiftEffectView removeFromSuperview];
|
|
|
|
|
self.luckyVapGiftEffectView = nil;
|
|
|
|
|
}
|
2025-01-15 19:02:58 +08:00
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)viewDidFailPlayMP4:(NSError *)error{
|
|
|
|
|
[self playVAGFailure];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)loadVapImageWithURL:(NSString *)urlStr
|
|
|
|
|
context:(NSDictionary *)context
|
|
|
|
|
completion:(VAPImageCompletionBlock)completionBlock {
|
|
|
|
|
if (self.mp4TempReceiveInfoModel) {
|
|
|
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
|
|
QGVAPSourceInfo *info = (QGVAPSourceInfo *)context[@"resource"];
|
|
|
|
|
|
2025-04-02 11:04:07 +08:00
|
|
|
|
// NSLog(@" MP4 的 key - info.contentTag : %@", info.contentTag);
|
2025-01-15 19:02:58 +08:00
|
|
|
|
[self _loadMP4AvatarURL:urlStr
|
|
|
|
|
info:info
|
|
|
|
|
completion:completionBlock];
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)_loadMP4AvatarURL:(NSString *)urlStr
|
|
|
|
|
info:(QGVAPSourceInfo *)info
|
|
|
|
|
completion:(VAPImageCompletionBlock)completionBlock {
|
|
|
|
|
NSString *path = @"";
|
|
|
|
|
switch (self.mp4TempReceiveInfoModel.gift.showAvatarType) {
|
|
|
|
|
case 1: // 只使用 avatar
|
|
|
|
|
case 3:
|
|
|
|
|
path = self.mp4TempReceiveInfoModel.avatar;
|
|
|
|
|
if ([NSString isEmpty:path]) {
|
|
|
|
|
path = self.mp4TempReceiveInfoModel.sendUserAvatar;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 2: // 只使用 target avatar
|
|
|
|
|
path = self.mp4TempReceiveInfoModel.targetAvatar;
|
|
|
|
|
if ([NSString isEmpty:path]) {
|
|
|
|
|
path = self.mp4TempReceiveInfoModel.recvUserAvatar;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ([NSString isEmpty:path]) {
|
|
|
|
|
completionBlock(kImage(@"common_avatar"), nil, @"dafeult image");
|
|
|
|
|
} else {
|
|
|
|
|
NetImageView *avatar_Loader = [[NetImageView alloc] init];
|
|
|
|
|
[avatar_Loader loadImageWithUrl:path
|
|
|
|
|
completion:^(UIImage * _Nullable image, NSURL * _Nonnull url) {
|
|
|
|
|
completionBlock(image, nil, urlStr);
|
|
|
|
|
}];
|
|
|
|
|
|
|
|
|
|
[self.mp4AvatarLoaders addObject:avatar_Loader];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma mark - PAGViewListener
|
|
|
|
|
- (void)onAnimationEnd:(PAGView*)pagView{
|
|
|
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
|
|
pagView.hidden = YES;
|
|
|
|
|
if (pagView == self.pagGiftEffectView) {
|
|
|
|
|
self.isPlayingGiftEffect = NO;
|
|
|
|
|
}
|
|
|
|
|
else if(pagView == self.carPagEffectView){
|
|
|
|
|
[self.carPagEffectView removeFromSuperview];
|
|
|
|
|
self.carPagEffectView = nil;
|
|
|
|
|
[self nextCarEffect];
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)onAnimationCancel:(PAGView*)pagView{
|
|
|
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
|
|
pagView.hidden = YES;
|
|
|
|
|
if (pagView == self.pagGiftEffectView) {
|
|
|
|
|
self.isPlayingGiftEffect = NO;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma mark - RoomHostDelegate
|
|
|
|
|
#pragma mark - RoomGuestDelegate: NIMCustomMessage
|
|
|
|
|
- (void)handleNIMCustomMessage:(NIMMessage *)message {
|
|
|
|
|
if (![message.messageObject isKindOfClass:[NIMCustomObject class]]) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
NIMCustomObject *obj = (NIMCustomObject *)message.messageObject;
|
|
|
|
|
if (obj.attachment == nil || ![obj.attachment isKindOfClass:[AttachmentModel class]]) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AttachmentModel *attachment = (AttachmentModel *)obj.attachment;
|
|
|
|
|
switch (attachment.first) {
|
2025-02-28 19:04:09 +08:00
|
|
|
|
case CustomMessageType_User_Enter_Room:
|
|
|
|
|
[self _handleEnterRoomMessage:message];
|
|
|
|
|
break;
|
|
|
|
|
case CustomMessageType_RedPacket:
|
|
|
|
|
[self _handleLuckyPackageMessage:attachment];
|
|
|
|
|
break;
|
2025-01-15 19:02:58 +08:00
|
|
|
|
case CustomMessageType_Gift:
|
|
|
|
|
[self _handleGiftMessage:attachment];
|
|
|
|
|
break;
|
|
|
|
|
case CustomMessageType_AllMicroSend:
|
|
|
|
|
[self _handleGiftMessage:attachment];
|
|
|
|
|
break;
|
|
|
|
|
case CustomMessageType_Car_Notify:
|
|
|
|
|
[self handleCarEnter:attachment];
|
|
|
|
|
break;
|
|
|
|
|
case CustomMessageType_CP:
|
|
|
|
|
[self receiveCPEvent:attachment];
|
|
|
|
|
break;
|
|
|
|
|
case CustomMessageType_Super_Gift:
|
|
|
|
|
[self _handleSuperGift:attachment];
|
|
|
|
|
break;
|
|
|
|
|
case CustomMessageType_General_Floating_Screen:
|
|
|
|
|
[self _handleCommonBanner:attachment];
|
|
|
|
|
break;
|
|
|
|
|
case CustomMessageType_LuckyBag:
|
2025-01-16 16:00:12 +08:00
|
|
|
|
[self handleLuckyBag:attachment];
|
2025-01-15 19:02:58 +08:00
|
|
|
|
break;
|
|
|
|
|
case CustomMessageType_Look_Love:
|
2025-01-16 16:00:12 +08:00
|
|
|
|
[self handle98:attachment];
|
2025-01-15 19:02:58 +08:00
|
|
|
|
break;
|
|
|
|
|
case CustomMessageType_RoomPlay_Dating:
|
2025-01-16 16:00:12 +08:00
|
|
|
|
[self handleDating:attachment];
|
2025-01-15 19:02:58 +08:00
|
|
|
|
break;
|
|
|
|
|
case CustomMessageType_Across_Room_PK:
|
2025-01-16 16:00:12 +08:00
|
|
|
|
[self handleAcrossRoomPK:attachment];
|
2025-01-15 19:02:58 +08:00
|
|
|
|
break;
|
|
|
|
|
case CustomMessageType_Anchor_FansTeam:
|
2025-01-16 16:00:12 +08:00
|
|
|
|
[self handleAnchorFansTeam:attachment];
|
2025-01-15 19:02:58 +08:00
|
|
|
|
break;
|
|
|
|
|
case CustomMessageType_Anchor_Hour_Rank:
|
2025-01-16 16:00:12 +08:00
|
|
|
|
[self handleAnchorHourRank:attachment];
|
2025-01-15 19:02:58 +08:00
|
|
|
|
break;
|
|
|
|
|
case CustomMessageType_License_Hour_Rank:
|
2025-01-16 16:00:12 +08:00
|
|
|
|
[self handleLicenseHourRank:attachment];
|
2025-01-15 19:02:58 +08:00
|
|
|
|
break;
|
|
|
|
|
case CustomMessageType_Gift_Compound:
|
2025-01-16 16:00:12 +08:00
|
|
|
|
[self handle93:attachment];
|
2025-01-15 19:02:58 +08:00
|
|
|
|
break;
|
|
|
|
|
case CustomMessageType_Room_Sailing:
|
2025-01-16 16:00:12 +08:00
|
|
|
|
[self handle81:attachment];
|
2025-01-15 19:02:58 +08:00
|
|
|
|
break;
|
2025-01-16 16:00:12 +08:00
|
|
|
|
case CustomMessageType_Graffiti_Gift: {
|
|
|
|
|
[self receiveRoomGraffitiGift:attachment];
|
|
|
|
|
}
|
2025-01-15 19:02:58 +08:00
|
|
|
|
break;
|
|
|
|
|
case CustomMessageType_Graffiti_Star_Kitchen:
|
2025-01-16 16:00:12 +08:00
|
|
|
|
[self handle104:attachment];
|
2025-01-15 19:02:58 +08:00
|
|
|
|
break;
|
|
|
|
|
case CustomMessageType_Treasure_Fairy:
|
2025-01-16 16:00:12 +08:00
|
|
|
|
[self handleFairy:attachment];
|
2025-01-15 19:02:58 +08:00
|
|
|
|
break;
|
|
|
|
|
case CustomMessageType_Tarot:
|
2025-01-16 16:00:12 +08:00
|
|
|
|
[self handleTarot:attachment];
|
2025-01-15 19:02:58 +08:00
|
|
|
|
break;
|
|
|
|
|
case CustomMessageType_Common_H5:
|
2025-01-16 16:00:12 +08:00
|
|
|
|
[self handleCommonH5:attachment];
|
2025-01-15 19:02:58 +08:00
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-28 19:04:09 +08:00
|
|
|
|
- (void)_handleEnterRoomMessage:(NIMMessage *)message {
|
|
|
|
|
NIMCustomObject *obj = (NIMCustomObject *)message.messageObject;
|
|
|
|
|
if (obj.attachment == nil || ![obj.attachment isKindOfClass:[AttachmentModel class]]) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AttachmentModel *attachment = (AttachmentModel *)obj.attachment;
|
|
|
|
|
switch (attachment.second) {
|
|
|
|
|
case Custom_Message_Sub_User_Enter_Room: {
|
|
|
|
|
RoomEnterModel *model = [RoomEnterModel modelWithJSON:attachment.data];
|
|
|
|
|
if (model.platformRole == 1) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (model.enterHide) {
|
|
|
|
|
//隐身进房
|
2025-06-16 17:30:20 +08:00
|
|
|
|
if (model.uid == [AccountInfoStorage instance].getUid.integerValue) {
|
2025-02-28 19:04:09 +08:00
|
|
|
|
[self createEnterHideAnimation];
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
NSString *userName = model.nick;
|
|
|
|
|
if (model.cpList.count > 0 && model.screenType < 3) {
|
2025-03-06 15:26:44 +08:00
|
|
|
|
NSString *title = [NSString stringWithFormat:YMLocalizedString(@"XPRoomAnimationView0"), userName];
|
|
|
|
|
NSDictionary * dic= @{@"title":title,
|
|
|
|
|
@"experLevelSeq":[NSString stringWithFormat:@"%ld", model.experLevelSeq],
|
|
|
|
|
@"effectPath" : @"",
|
|
|
|
|
@"isCP":@(YES)
|
|
|
|
|
};
|
|
|
|
|
[self.enterRoomAnimationQueue addObject:dic];
|
2025-02-28 19:04:09 +08:00
|
|
|
|
} else {
|
|
|
|
|
NSString *title = [NSString stringWithFormat:YMLocalizedString(@"XPRoomAnimationView0"), userName];
|
|
|
|
|
|
|
|
|
|
NSDictionary * dic= @{@"title":title,
|
|
|
|
|
@"experLevelSeq":[NSString stringWithFormat:@"%ld", model.experLevelSeq],
|
|
|
|
|
@"effectPath" : model.enterRoomEffects.length ? model.enterRoomEffects : @""};
|
|
|
|
|
[self.enterRoomAnimationQueue addObject:dic];
|
|
|
|
|
}
|
|
|
|
|
[self tryDequeueAnimation];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)_handleLuckyPackageMessage:(AttachmentModel *)attachment {
|
|
|
|
|
if ([self _isInSudGame]) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (attachment.second) {
|
|
|
|
|
case Custom_Message_Sub_LuckyPackage:
|
|
|
|
|
[self receiveLuckGiftBanner:attachment];
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-15 19:02:58 +08:00
|
|
|
|
- (void)_handleGiftMessage:(AttachmentModel *)attachment {
|
|
|
|
|
if ([self _isInSudGame]) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-18 14:01:57 +08:00
|
|
|
|
NSLog(@"[Combo effect] 📨 收到礼物消息 - second: %ld", (long)attachment.second);
|
2025-01-15 19:02:58 +08:00
|
|
|
|
GiftReceiveInfoModel * receiveInfo = [GiftReceiveInfoModel modelWithJSON:attachment.data];
|
|
|
|
|
[receiveInfo giftDataAlignment];
|
|
|
|
|
|
2025-08-18 14:01:57 +08:00
|
|
|
|
// 检查并修复连击计数
|
|
|
|
|
if (receiveInfo.comboCount < 1) {
|
|
|
|
|
NSLog(@"[Combo effect] 🚨 收到云信消息中连击计数异常 - comboCount: %ld", (long)receiveInfo.comboCount);
|
|
|
|
|
// 尝试从 attachment.data 中获取正确的连击计数
|
|
|
|
|
NSNumber *dataComboCount = attachment.data[@"comboCount"];
|
|
|
|
|
if (dataComboCount && [dataComboCount integerValue] >= 1) {
|
|
|
|
|
NSLog(@"[Combo effect] 🔧 从 attachment.data 修复连击计数 - 修复为: %@", dataComboCount);
|
|
|
|
|
receiveInfo.comboCount = [dataComboCount integerValue];
|
|
|
|
|
} else {
|
|
|
|
|
NSLog(@"[Combo effect] 🔧 设置默认连击计数为 1");
|
|
|
|
|
receiveInfo.comboCount = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NSLog(@"[Combo effect] 📨 礼物消息解析完成 - giftId: %ld, combo: %ld, uid: %@", (long)receiveInfo.gift.giftId, (long)receiveInfo.comboCount, receiveInfo.uid);
|
|
|
|
|
|
2025-02-28 19:04:09 +08:00
|
|
|
|
receiveInfo.isLuckyBagGift = (attachment.second == Custom_Message_Sub_Gift_LuckySend ||
|
|
|
|
|
attachment.second == Custom_Message_Sub_AllMicroLuckySend ||
|
|
|
|
|
attachment.second == Custom_Message_Sub_AllBatchMicroLuckySend);
|
2025-01-15 19:02:58 +08:00
|
|
|
|
receiveInfo.isBatch = (attachment.second == Custom_Message_Sub_AllBatchSend ||
|
|
|
|
|
attachment.second == Custom_Message_Sub_AllBatchMicroLuckySend);
|
|
|
|
|
receiveInfo.isComboBatch = (attachment.second == Custom_Message_Sub_AllMicroSend);
|
|
|
|
|
|
|
|
|
|
switch (attachment.second) {
|
|
|
|
|
case Custom_Message_Sub_Gift_Send:
|
|
|
|
|
[self _handleGift:receiveInfo attachment:attachment];
|
|
|
|
|
break;
|
|
|
|
|
case Custom_Message_Sub_AllMicroSend:
|
2025-01-22 21:22:58 +08:00
|
|
|
|
case Custom_Message_Sub_AllBatchSend:
|
2025-01-15 19:02:58 +08:00
|
|
|
|
[self _handleGift:receiveInfo attachment:attachment];
|
|
|
|
|
break;
|
|
|
|
|
case Custom_Message_Sub_Gift_ChannelNotify:
|
|
|
|
|
//处理原广播通用飘屏 banner 逻辑
|
|
|
|
|
[self receiveRoomGiftBanner:attachment];
|
|
|
|
|
return;
|
|
|
|
|
break;
|
|
|
|
|
case Custom_Message_Sub_Gift_EmbeddedStyle:
|
|
|
|
|
[self _handleGiftEmbeddedStyle:receiveInfo attachment:attachment];
|
|
|
|
|
break;
|
2025-02-28 19:04:09 +08:00
|
|
|
|
case 607:
|
|
|
|
|
[self receiveLuckGiftBanner:attachment];
|
|
|
|
|
break;
|
|
|
|
|
case Custom_Message_Sub_Gift_LuckySend:
|
|
|
|
|
case Custom_Message_Sub_AllMicroLuckySend:
|
|
|
|
|
case Custom_Message_Sub_AllBatchMicroLuckySend:
|
|
|
|
|
{
|
|
|
|
|
[self _handleGift:receiveInfo attachment:attachment];
|
|
|
|
|
// if (receiveInfo.mp4Url.length > 0) {
|
|
|
|
|
// [self playLuckyGiftEffectWithVapUrl:receiveInfo.mp4Url];
|
|
|
|
|
// } else {
|
|
|
|
|
// NSString * svgaString = receiveInfo.luckyGiftSvgaUrl.length > 0 ? receiveInfo.luckyGiftSvgaUrl : receiveInfo.gift.luckyGiftSvgaUrl;
|
|
|
|
|
// NSURL * luckyGiftSvgaUrl = [NSURL URLWithString:svgaString];
|
|
|
|
|
// if (luckyGiftSvgaUrl.absoluteString.length > 0) {
|
|
|
|
|
// [self play:luckyGiftSvgaUrl];
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
|
|
|
|
// [self receiveGift:receiveInfo];
|
|
|
|
|
// });
|
|
|
|
|
}
|
|
|
|
|
break;
|
2025-01-15 19:02:58 +08:00
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (receiveInfo.isLuckyBagGift) {
|
2025-08-18 14:01:57 +08:00
|
|
|
|
NSLog(@"[Combo effect] 🎁 处理福袋礼物");
|
2025-01-15 19:02:58 +08:00
|
|
|
|
[self receiveGiftHandleSendGiftAnimationWith:receiveInfo
|
|
|
|
|
attachment:attachment];
|
|
|
|
|
[self _handleBagGift:receiveInfo];
|
|
|
|
|
} else {
|
|
|
|
|
if (receiveInfo.gift.notifyFull == 1 &&
|
|
|
|
|
attachment.second == Custom_Message_Sub_Gift_Send) {
|
|
|
|
|
// 全服礼物,但由自己发送,不在此逻辑播放
|
2025-08-18 14:01:57 +08:00
|
|
|
|
NSLog(@"[Combo effect] 🎁 全服礼物由自己发送,跳过播放");
|
2025-01-15 19:02:58 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
2025-02-28 19:04:09 +08:00
|
|
|
|
// 处理从位置 发送者 到 接受者 的礼物移动动画
|
2025-08-18 14:01:57 +08:00
|
|
|
|
NSLog(@"[Combo effect] 🎁 处理普通礼物动画");
|
2025-01-15 19:02:58 +08:00
|
|
|
|
[self receiveGiftHandleSendGiftAnimationWith:receiveInfo
|
|
|
|
|
attachment:attachment];
|
2025-02-28 19:04:09 +08:00
|
|
|
|
// 播放礼物动画(svga/mp4)(如果有的话)
|
2025-01-15 19:02:58 +08:00
|
|
|
|
[self receiveGift:receiveInfo];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)_handleBagGift:(GiftReceiveInfoModel *)receiveInfo {
|
|
|
|
|
if (!self.hostDelegate.getRoomInfo.hasAnimationEffect) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
[self receiveGift:receiveInfo];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)_handleGift:(GiftReceiveInfoModel *)receiveInfo
|
|
|
|
|
attachment:(AttachmentModel *)attachment {
|
|
|
|
|
// 确认接受者有 uid
|
|
|
|
|
if (receiveInfo.targetUsers.count == 0) {
|
|
|
|
|
GiftReceiveUserInfoModel *model = [[GiftReceiveUserInfoModel alloc] init];
|
|
|
|
|
model.nick = receiveInfo.targetNick;
|
|
|
|
|
model.avatar = receiveInfo.targetAvatar;
|
|
|
|
|
model.uid = receiveInfo.uid.integerValue;
|
|
|
|
|
receiveInfo.targetUsers = @[model];
|
|
|
|
|
}
|
2025-05-06 16:45:34 +08:00
|
|
|
|
// 确认接受者有 uid
|
|
|
|
|
if (receiveInfo.targetUsers.count > 0 && receiveInfo.targetUids.count <= 0) {
|
|
|
|
|
receiveInfo.targetUids = [receiveInfo.targetUsers valueForKeyPath:@"uid"];
|
2025-01-15 19:02:58 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)_handleGiftEmbeddedStyle:(GiftReceiveInfoModel *)receiveInfo
|
|
|
|
|
attachment:(AttachmentModel *)attachment {
|
|
|
|
|
// 数据对齐
|
|
|
|
|
receiveInfo.targetUid = [[attachment.data objectForKey:@"recvUserUid"] stringValue];
|
|
|
|
|
receiveInfo.targetNick = [attachment.data objectForKey:@"recvUserNick"];
|
|
|
|
|
receiveInfo.targetAvatar = [attachment.data objectForKey:@"recvUserAvatar"];
|
|
|
|
|
receiveInfo.avatar = [attachment.data objectForKey:@"sendUserAvatar"];
|
|
|
|
|
receiveInfo.nick = [attachment.data objectForKey:@"sendUserNick"];
|
|
|
|
|
receiveInfo.uid = [[attachment.data objectForKey:@"sendUserUid"] stringValue];
|
|
|
|
|
|
|
|
|
|
// 确认接受者有 uid
|
|
|
|
|
if (receiveInfo.targetUsers.count > 0 && receiveInfo.targetUids.count <= 0) {
|
|
|
|
|
receiveInfo.targetUids = [receiveInfo.targetUsers valueForKeyPath:@"uid"];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)_handleSuperGift:(AttachmentModel *)attachment {
|
|
|
|
|
switch (attachment.second) {
|
|
|
|
|
case Custom_Message_Sub_Super_Gift_Winning_Coins:
|
|
|
|
|
[self receiveLuckGiftWinning:attachment];
|
|
|
|
|
break;
|
|
|
|
|
case Custom_Message_Sub_Super_Gift_Winning_Coins_ALL_Room:
|
|
|
|
|
[self receiveLuckGiftBanner:attachment];
|
|
|
|
|
break;
|
2025-04-02 11:04:07 +08:00
|
|
|
|
case Custom_Message_Sub_Super_Gift_Banner:
|
|
|
|
|
[self handleBroveGiftBanner:attachment];
|
|
|
|
|
break;
|
|
|
|
|
case Custom_Message_Sub_Super_Gift_UI_Rffect:
|
2025-04-21 13:52:13 +08:00
|
|
|
|
[self receiveBravoGiftWinning:attachment];
|
2025-01-15 19:02:58 +08:00
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)_handleCommonBanner:(AttachmentModel *)attachment {
|
|
|
|
|
switch (attachment.second) {
|
|
|
|
|
case Custom_Message_Sub_General_Floating_Screen_One_Room:
|
|
|
|
|
case Custom_Message_Sub_General_Floating_Screen_All_Room:
|
|
|
|
|
[self receiveRoomGeneralFloatingScreen:attachment];
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString *)_findFullPath:(NSString *)url {
|
|
|
|
|
NSString *encodingUrl = [url pureURLString];
|
|
|
|
|
NSString *fileName = [[encodingUrl componentsSeparatedByString:@"/"] lastObject];
|
|
|
|
|
NSString *fullPath = [self.GiftDynamicEffectListPath stringByAppendingPathComponent:fileName];
|
|
|
|
|
return fullPath;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)_updateGiftEffectContentMode:(UIView *)view
|
|
|
|
|
size:(CGSize)size {
|
|
|
|
|
CGFloat width = size.width;
|
|
|
|
|
CGFloat height = size.height;
|
|
|
|
|
if (width > height) {
|
|
|
|
|
view.contentMode = UIViewContentModeScaleAspectFit;
|
|
|
|
|
} else {//高大于宽
|
|
|
|
|
CGFloat resizeH = KScreenWidth * height / width;//按照屏幕的宽度去缩放,获得高度
|
|
|
|
|
if (resizeH > KScreenHeight) {//如果大于屏幕高度,填充
|
|
|
|
|
view.contentMode = UIViewContentModeScaleAspectFill;
|
|
|
|
|
} else {//小于屏幕高度,
|
|
|
|
|
view.contentMode = UIViewContentModeScaleAspectFit;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-16 16:00:12 +08:00
|
|
|
|
- (void)handleCommonH5:(AttachmentModel *)attachment {
|
|
|
|
|
if (!attachment) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (attachment.second) {
|
2025-08-12 13:53:12 +08:00
|
|
|
|
|
2025-01-16 16:00:12 +08:00
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)handleTarot:(AttachmentModel *)attachment {
|
|
|
|
|
if (!attachment) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
switch (attachment.second) {
|
2025-08-12 13:53:12 +08:00
|
|
|
|
|
2025-01-16 16:00:12 +08:00
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)handleFairy:(AttachmentModel *)attachment {
|
|
|
|
|
if (!attachment) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
switch (attachment.second) {
|
|
|
|
|
case Custom_Message_Sub_Treasure_Fairy_Draw_Gift_L4:
|
|
|
|
|
case Custom_Message_Sub_Treasure_Fairy_Draw_Gift_L5:
|
|
|
|
|
case Custom_Message_Sub_Treasure_Fairy_Convert_L1:
|
|
|
|
|
case Custom_Message_Sub_Treasure_Fairy_Convert_L2:
|
|
|
|
|
case Custom_Message_Sub_Treasure_Fairy_Convert_L3:
|
|
|
|
|
[self receiveTreasureFairyGiftHighLevel:attachment];
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)handle98:(AttachmentModel *)attachment {
|
|
|
|
|
if (!attachment) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
switch (attachment.second) {
|
|
|
|
|
case Custom_Message_Sub_Look_Love_InRoom_NeedAllMicSend:
|
|
|
|
|
[self receiveCandyTreeGiftHighLevle:attachment];
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)handle104:(AttachmentModel *)attachment {
|
|
|
|
|
if (!attachment) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
switch (attachment.second) {
|
2025-08-12 14:07:38 +08:00
|
|
|
|
|
2025-01-16 16:00:12 +08:00
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)handleLuckyBag:(AttachmentModel *)attachment {
|
|
|
|
|
if (!attachment) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
switch (attachment.second) {
|
|
|
|
|
case Custom_Message_Sub_Room_Gift_LuckBag_FullScree:
|
2025-02-28 19:04:09 +08:00
|
|
|
|
case Custom_Message_Sub_Room_Gift_LuckBag_Server:
|
2025-01-16 16:00:12 +08:00
|
|
|
|
[self receiveLuckyGiftBigPrize:attachment];
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)handleVIPLevelUp:(AttachmentModel *)attachment {
|
|
|
|
|
if (!attachment) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
switch (attachment.second) {
|
|
|
|
|
case Custom_Message_Sub_Room_Noble_LevelUp_Suspend:
|
|
|
|
|
[self receiveNobleLevelUp:attachment];
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)handleDating:(AttachmentModel *)attachment {
|
|
|
|
|
if (!attachment) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
switch (attachment.second) {
|
|
|
|
|
case Custom_Message_Sub_Room_Play_Dating_Public_Result:
|
|
|
|
|
[self roomDatingPublicResult:attachment];
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)handleAcrossRoomPK:(AttachmentModel *)attachment {
|
|
|
|
|
if (!attachment) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
switch (attachment.second) {
|
|
|
|
|
case Custom_Message_Sub_AcrossRoomPK_Result:
|
|
|
|
|
[self acrossRoomPKBannerAnimation:attachment];
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)handleAnchorFansTeam:(AttachmentModel *)attachment {
|
|
|
|
|
if (!attachment) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
switch (attachment.second) {
|
|
|
|
|
case Custom_Message_Sub_FansTeam_Join_Success: {
|
|
|
|
|
GiftReceiveInfoModel *receiveInfo = [[GiftReceiveInfoModel alloc] init];
|
|
|
|
|
GiftInfoModel *giftInfo = [GiftInfoModel modelWithJSON:attachment.data[@"giftVo"]];
|
|
|
|
|
receiveInfo.gift = giftInfo;
|
|
|
|
|
receiveInfo.giftInfo = giftInfo;
|
|
|
|
|
[self receiveFansTeamGiftHandleSendGiftAnimation:attachment];
|
|
|
|
|
[self receiveGift:receiveInfo];
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)handleAnchorHourRank:(AttachmentModel *)attachment {
|
|
|
|
|
if (!attachment) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
switch (attachment.second) {
|
|
|
|
|
case Custom_Message_Sub_Anchor_Hour_Rank:
|
|
|
|
|
[self receiveAnchorHourRank:attachment];
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)handleLicenseHourRank:(AttachmentModel *)attachment {
|
|
|
|
|
if (!attachment) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
switch (attachment.second) {
|
|
|
|
|
case Custom_Message_Sub_License_Hour_Rank:
|
|
|
|
|
[self receiveAnchorHourRank:attachment];
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)handle93:(AttachmentModel *)attachment {
|
|
|
|
|
if (!attachment) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
switch (attachment.second) {
|
|
|
|
|
case Custom_Message_Sub_Gift_Compound:
|
|
|
|
|
[self receiveGiftCompound:attachment];
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)handle81:(AttachmentModel *)attachment {
|
|
|
|
|
if (!attachment) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
switch (attachment.second) {
|
|
|
|
|
case Custom_Message_Sub_Sailing_AllRoom_Notify:
|
|
|
|
|
case Custom_Message_Sub_Sailing_InRoom_NeedAllMicSend:
|
|
|
|
|
[self receiveRoomSailing:attachment];
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-02 11:04:07 +08:00
|
|
|
|
- (void)handleBroveGiftBanner:(AttachmentModel *)attachment {
|
|
|
|
|
[self inserBannerModelToQueue:attachment];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2025-01-15 19:02:58 +08:00
|
|
|
|
#pragma mark - RoomGuestDelegate: NIMNotificationMessageDelegate
|
|
|
|
|
- (void)handleNIMNotificationMessage:(NIMMessage *)message {
|
2025-02-28 19:04:09 +08:00
|
|
|
|
return;
|
|
|
|
|
// NIMNotificationObject *notiMsg = (NIMNotificationObject *)message.messageObject;
|
|
|
|
|
// NIMChatroomNotificationContent *content = (NIMChatroomNotificationContent *)notiMsg.content;
|
|
|
|
|
// if (!content) {
|
|
|
|
|
// return;
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// switch (content.eventType) {
|
|
|
|
|
// case NIMChatroomEventTypeEnter:
|
|
|
|
|
// [self enterRoom:message content:content];
|
|
|
|
|
// break;
|
|
|
|
|
//
|
|
|
|
|
// default:
|
|
|
|
|
// break;
|
|
|
|
|
// }
|
2025-01-15 19:02:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma mark - NIMBroadcastManagerDelegate
|
|
|
|
|
- (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.hostDelegate.getUserInfo.partitionId]){
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (attachment.first) {
|
|
|
|
|
case CustomMessageType_General_Floating_Screen:
|
|
|
|
|
[self _handleCommonBanner:attachment];
|
|
|
|
|
break;
|
2025-01-16 16:00:12 +08:00
|
|
|
|
case CustomMessageType_Noble_VIP:
|
|
|
|
|
[self handleVIPLevelUp:attachment];
|
|
|
|
|
break;
|
|
|
|
|
case CustomMessageType_LuckyBag:
|
|
|
|
|
[self handleLuckyBag:attachment];
|
|
|
|
|
break;
|
|
|
|
|
case CustomMessageType_Graffiti_Star_Kitchen:
|
|
|
|
|
[self handle104:attachment];
|
|
|
|
|
break;
|
|
|
|
|
case CustomMessageType_Look_Love:
|
|
|
|
|
[self handle98:attachment];
|
|
|
|
|
break;
|
|
|
|
|
case CustomMessageType_Treasure_Fairy:
|
|
|
|
|
[self handleFairy:attachment];
|
|
|
|
|
break;
|
|
|
|
|
case CustomMessageType_Tarot:
|
|
|
|
|
[self handleTarot:attachment];
|
|
|
|
|
break;
|
|
|
|
|
case CustomMessageType_Common_H5:
|
|
|
|
|
[self handleCommonH5:attachment];
|
|
|
|
|
break;
|
2025-01-15 19:02:58 +08:00
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma mark - GiftAnimationManagerDelegate
|
|
|
|
|
- (CGPoint)animationPointAtStageViewByUid:(NSString *)uid {
|
|
|
|
|
return [self.hostDelegate animationPointAtStageViewByUid:uid];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma mark - Gesture
|
|
|
|
|
- (void)addBnnerContainGesture {
|
2025-08-15 19:34:25 +08:00
|
|
|
|
[self insertSubview:self.bannerSwipeGestureContainer aboveSubview:self.bannerContainer];
|
|
|
|
|
[self insertSubview:self.bannerLeftTapGestureContainer aboveSubview:self.bannerContainer];
|
|
|
|
|
[self insertSubview:self.bannerRightTapGestureContainer aboveSubview:self.bannerContainer];
|
|
|
|
|
|
|
|
|
|
[self.bannerSwipeGestureContainer mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
|
|
make.center.mas_equalTo(self.bannerContainer);
|
|
|
|
|
make.top.bottom.mas_equalTo(self.bannerContainer);
|
|
|
|
|
make.width.mas_equalTo(self.bannerContainer.mas_width).multipliedBy(2.0/3.0);
|
|
|
|
|
}];
|
|
|
|
|
|
|
|
|
|
[self.bannerLeftTapGestureContainer mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
|
|
make.top.leading.bottom.mas_equalTo(self.bannerContainer);
|
|
|
|
|
make.trailing.mas_equalTo(self.bannerSwipeGestureContainer.mas_leading);
|
|
|
|
|
}];
|
|
|
|
|
|
|
|
|
|
[self.bannerRightTapGestureContainer mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
|
|
make.top.trailing.bottom.mas_equalTo(self.bannerContainer);
|
|
|
|
|
make.leading.mas_equalTo(self.bannerSwipeGestureContainer.mas_trailing);
|
|
|
|
|
}];
|
|
|
|
|
|
|
|
|
|
// 创建中央区域的 swipe 手势(2/3 宽度)
|
2025-01-15 19:02:58 +08:00
|
|
|
|
UISwipeGestureRecognizer *swipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self
|
|
|
|
|
action:@selector(handleSwipe)];
|
2025-01-22 21:22:58 +08:00
|
|
|
|
if (isMSRTL()) {
|
|
|
|
|
swipe.direction = UISwipeGestureRecognizerDirectionRight;
|
|
|
|
|
} else {
|
|
|
|
|
swipe.direction = UISwipeGestureRecognizerDirectionLeft;
|
|
|
|
|
}
|
2025-08-15 19:34:25 +08:00
|
|
|
|
swipe.delegate = self;
|
|
|
|
|
|
|
|
|
|
// 创建中央区域的 tap 手势(2/3 宽度)
|
|
|
|
|
UITapGestureRecognizer *centerTap = [[UITapGestureRecognizer alloc] initWithTarget:self
|
|
|
|
|
action:@selector(handleBannerTap:)];
|
|
|
|
|
centerTap.delegate = self;
|
|
|
|
|
|
|
|
|
|
// 创建左侧区域的 tap 手势(1/6 宽度)
|
|
|
|
|
UITapGestureRecognizer *leftTap = [[UITapGestureRecognizer alloc] initWithTarget:self
|
|
|
|
|
action:@selector(handleBannerTap:)];
|
|
|
|
|
leftTap.delegate = self;
|
|
|
|
|
|
|
|
|
|
// 创建右侧区域的 tap 手势(1/6 宽度)
|
|
|
|
|
UITapGestureRecognizer *rightTap = [[UITapGestureRecognizer alloc] initWithTarget:self
|
|
|
|
|
action:@selector(handleBannerTap:)];
|
|
|
|
|
rightTap.delegate = self;
|
2025-01-22 21:22:58 +08:00
|
|
|
|
|
2025-08-15 19:34:25 +08:00
|
|
|
|
// 只有当 swipe 判定失败后,tap 才允许成功
|
|
|
|
|
[centerTap requireGestureRecognizerToFail:swipe];
|
|
|
|
|
|
|
|
|
|
// 添加手势识别器
|
|
|
|
|
[self.bannerSwipeGestureContainer addGestureRecognizer:swipe];
|
|
|
|
|
[self.bannerSwipeGestureContainer addGestureRecognizer:centerTap];
|
|
|
|
|
[self.bannerLeftTapGestureContainer addGestureRecognizer:leftTap];
|
|
|
|
|
[self.bannerRightTapGestureContainer addGestureRecognizer:rightTap];
|
2025-01-15 19:02:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)handleSwipe {
|
|
|
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:@"SwipeOutBanner" object:nil];
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-15 19:34:25 +08:00
|
|
|
|
- (void)handleBannerTap:(UITapGestureRecognizer *)tapGesture {
|
|
|
|
|
CGPoint tapPoint = [tapGesture locationInView:self.bannerContainer];
|
|
|
|
|
|
|
|
|
|
// 检查当前显示的 banner 是否在 tap 位置可以响应事件
|
|
|
|
|
if ([self isPointInBannerInteractiveArea:tapPoint]) {
|
|
|
|
|
// banner 可以响应,不处理,让 banner 继续原有逻辑
|
|
|
|
|
NSLog(@"🎯 Banner tap 位置在可交互区域,banner 将处理此事件");
|
|
|
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:@"TapBanner"
|
|
|
|
|
object:nil
|
|
|
|
|
userInfo:@{@"point": [NSValue valueWithCGPoint:tapPoint]}];
|
|
|
|
|
} else {
|
|
|
|
|
// banner 不能响应,保存 tap 位置
|
|
|
|
|
self.savedTapPoint = tapPoint;
|
|
|
|
|
self.hasSavedTapPoint = YES;
|
|
|
|
|
NSLog(@"💾 Banner tap 位置不在可交互区域,已保存位置: %@", NSStringFromCGPoint(tapPoint));
|
|
|
|
|
// 将 bannerContainer 中的点转换为屏幕坐标系
|
|
|
|
|
CGPoint screenPoint = [self.bannerContainer convertPoint:tapPoint toView:nil];
|
|
|
|
|
// UIView *tappedView = tapGesture.view;
|
|
|
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:@"BannerTapToFunctionContainer"
|
|
|
|
|
object:nil
|
|
|
|
|
userInfo:@{@"point": [NSValue valueWithCGPoint:screenPoint]}];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL)isPointInBannerInteractiveArea:(CGPoint)point {
|
|
|
|
|
// 检查当前显示的 banner 是否在指定位置可以响应事件
|
|
|
|
|
for (UIView *subview in self.bannerContainer.subviews) {
|
|
|
|
|
if (subview.hidden || subview.alpha <= 0.01) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查点是否在子视图范围内
|
|
|
|
|
if (CGRectContainsPoint(subview.bounds, point)) {
|
|
|
|
|
// 检查子视图是否支持用户交互
|
|
|
|
|
if (subview.userInteractionEnabled) {
|
|
|
|
|
// 进一步检查子视图是否有可点击的元素
|
|
|
|
|
CGPoint subviewPoint = [subview convertPoint:point fromView:self.bannerContainer];
|
|
|
|
|
UIView *hitView = [subview hitTest:subviewPoint withEvent:nil];
|
|
|
|
|
if (hitView && hitView.userInteractionEnabled) {
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma mark - UIGestureRecognizerDelegate
|
|
|
|
|
|
|
|
|
|
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
|
|
|
|
|
// 允许手势同时识别
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
|
|
|
|
|
CGPoint touchPoint = [touch locationInView:self.bannerContainer];
|
|
|
|
|
CGFloat containerWidth = self.bannerContainer.bounds.size.width;
|
|
|
|
|
|
|
|
|
|
// 计算区域边界
|
|
|
|
|
CGFloat leftBoundary = containerWidth / 6.0; // 1/6 宽度
|
|
|
|
|
CGFloat rightBoundary = containerWidth * 5.0 / 6.0; // 5/6 宽度
|
|
|
|
|
|
|
|
|
|
if ([gestureRecognizer isKindOfClass:[UISwipeGestureRecognizer class]]) {
|
|
|
|
|
// Swipe 手势只在中央 2/3 区域生效
|
|
|
|
|
return touchPoint.x >= leftBoundary && touchPoint.x <= rightBoundary;
|
|
|
|
|
} else if ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) {
|
|
|
|
|
// Tap 手势只在左右两侧 1/6 区域生效
|
|
|
|
|
// return touchPoint.x < leftBoundary || touchPoint.x > rightBoundary;
|
|
|
|
|
// 根据手势所在的容器来决定区域
|
|
|
|
|
if (gestureRecognizer.view == self.bannerSwipeGestureContainer) {
|
|
|
|
|
// 中央区域的 tap 手势
|
|
|
|
|
return touchPoint.x >= leftBoundary && touchPoint.x <= rightBoundary;
|
|
|
|
|
} else {
|
|
|
|
|
// 左右两侧的 tap 手势
|
|
|
|
|
return touchPoint.x < leftBoundary || touchPoint.x > rightBoundary;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-15 19:02:58 +08:00
|
|
|
|
#pragma mark - Animations
|
|
|
|
|
- (void)enterRoomAnimationFor:(UIView *)targetView
|
|
|
|
|
startFrom:(CGPoint)sfPoint
|
|
|
|
|
startTo:(CGPoint)stPoint
|
|
|
|
|
endFrom:(CGPoint)efPoint
|
|
|
|
|
endTo:(CGPoint)etPoint
|
|
|
|
|
duration:(CFTimeInterval)duration
|
|
|
|
|
completion:(void (^)(BOOL finished))completion {
|
|
|
|
|
@kWeakify(self);
|
|
|
|
|
[self enterRoomMoveInAnimationFor:targetView
|
|
|
|
|
fromValue:sfPoint
|
|
|
|
|
toValue:stPoint
|
|
|
|
|
completion:^(BOOL finished) {
|
|
|
|
|
if (finished) {
|
|
|
|
|
@kStrongify(self);
|
|
|
|
|
@kWeakify(self);
|
|
|
|
|
[self enterRoomMoveOutAnimationFor:targetView
|
|
|
|
|
fromValue:efPoint
|
|
|
|
|
toValue:etPoint
|
|
|
|
|
beginTime:duration
|
|
|
|
|
completion:^(BOOL finished) {
|
|
|
|
|
if (finished) {
|
|
|
|
|
@kStrongify(self);
|
|
|
|
|
[self cleanupAnimationsForView:targetView];
|
|
|
|
|
if (completion) {
|
|
|
|
|
completion(finished);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)enterRoomMoveInAnimationFor:(UIView *)view
|
|
|
|
|
fromValue:(CGPoint)fromValue
|
|
|
|
|
toValue:(CGPoint)toValue
|
|
|
|
|
completion:(void (^)(BOOL finished))completion {
|
|
|
|
|
POPSpringAnimation *springAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPViewCenter];
|
|
|
|
|
springAnimation.springSpeed = 12;
|
|
|
|
|
springAnimation.springBounciness = 10.f;
|
|
|
|
|
springAnimation.fromValue = [NSValue valueWithCGPoint:fromValue];
|
|
|
|
|
springAnimation.toValue = [NSValue valueWithCGPoint:toValue];
|
|
|
|
|
[springAnimation setCompletionBlock:^(POPAnimation *anim, BOOL finished) {
|
|
|
|
|
if (completion) completion(finished);
|
|
|
|
|
}];
|
|
|
|
|
[view pop_addAnimation:springAnimation forKey:@"amationSpringIn"];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)enterRoomMoveOutAnimationFor:(UIView *)view
|
|
|
|
|
fromValue:(CGPoint)fromValue
|
|
|
|
|
toValue:(CGPoint)toValue
|
|
|
|
|
beginTime:(CFTimeInterval)beginTime
|
|
|
|
|
completion:(void (^)(BOOL finished))completion {
|
|
|
|
|
POPSpringAnimation *moveAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPViewCenter];
|
|
|
|
|
moveAnimation.fromValue = [NSValue valueWithCGPoint:fromValue];
|
|
|
|
|
moveAnimation.toValue = [NSValue valueWithCGPoint:toValue];
|
|
|
|
|
moveAnimation.beginTime = beginTime;
|
|
|
|
|
moveAnimation.springSpeed = 8;
|
|
|
|
|
moveAnimation.springBounciness = 15.f;
|
|
|
|
|
[moveAnimation setCompletionBlock:^(POPAnimation *anim, BOOL finished) {
|
|
|
|
|
if (completion) completion(finished);
|
|
|
|
|
}];
|
|
|
|
|
[view pop_addAnimation:moveAnimation forKey:@"animetionMoveOut"];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)cleanupAnimationsForView:(UIView *)view {
|
|
|
|
|
[view pop_removeAllAnimations];
|
|
|
|
|
[view removeFromSuperview];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma mark - Common methods
|
|
|
|
|
- (NSString *)_resolveUserNameFromContent:(NIMChatroomNotificationContent *)content
|
|
|
|
|
extModel:(XPMessageRemoteExtModel *)extModel {
|
|
|
|
|
// 1) extModel.nick 优先
|
|
|
|
|
if (![NSString isEmpty:extModel.nick]) {
|
|
|
|
|
return extModel.nick;
|
|
|
|
|
}
|
|
|
|
|
// 2) 如果 extModel.nick 为空,看 content.source.nick
|
|
|
|
|
if (![NSString isEmpty:content.source.nick]) {
|
|
|
|
|
return content.source.nick;
|
|
|
|
|
}
|
|
|
|
|
// 3) 如果依然空,并且是自己,则取本地 nick
|
|
|
|
|
if (content.source.userId.intValue == self.hostDelegate.getUserInfo.uid &&
|
|
|
|
|
![NSString isEmpty:self.hostDelegate.getUserInfo.nick]) {
|
|
|
|
|
return self.hostDelegate.getUserInfo.nick;
|
|
|
|
|
}
|
|
|
|
|
// 4) 兜底
|
|
|
|
|
return @"";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString *)_mapExperLevelSeqToLocalKey:(NSInteger)seq {
|
|
|
|
|
if (seq >= 30 && seq <= 39) {
|
|
|
|
|
return @"experience_entre_effect_30";
|
|
|
|
|
} else if (seq >= 40 && seq <= 49) {
|
|
|
|
|
return @"experience_entre_effect_40";
|
|
|
|
|
} else if (seq >= 50 && seq <= 59) {
|
|
|
|
|
return @"experience_entre_effect_50";
|
|
|
|
|
} else if (seq >= 60 && seq <= 69) {
|
|
|
|
|
return @"experience_entre_effect_60";
|
|
|
|
|
} else if (seq >= 70 && seq <= 79) {
|
|
|
|
|
return @"experience_entre_effect_70";
|
|
|
|
|
} else if (seq >= 80 && seq <= 89) {
|
|
|
|
|
return @"experience_entre_effect_80";
|
|
|
|
|
} else if (seq >= 90) {
|
|
|
|
|
return @"experience_entre_effect_90";
|
|
|
|
|
}
|
|
|
|
|
return @"";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL)_isInSudGame {
|
|
|
|
|
BOOL isGamePlaying = NO;
|
|
|
|
|
if (self.hostDelegate.getRoomInfo.type == RoomType_MiniGame) {
|
|
|
|
|
NSInteger micCount = self.hostDelegate.getRoomInfo.mgMicNum;
|
|
|
|
|
for (int i = -1; i<micCount; i++) {
|
|
|
|
|
NSMutableDictionary * micQueue = self.hostDelegate.getMicroQueue;
|
|
|
|
|
MicroQueueModel *micSequence = [micQueue objectForKey:[NSString stringWithFormat:@"%d", i]];
|
|
|
|
|
if (micSequence == nil || micSequence.userInfo == nil) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (micSequence.userInfo.uid == [AccountInfoStorage instance].getUid.integerValue &&
|
|
|
|
|
micSequence.userInfo.gameStatus == LittleGamePlayStatus_Plying) {
|
|
|
|
|
isGamePlaying = YES;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return isGamePlaying;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)_addSubviewToMiddleContainer:(UIView *)view {
|
|
|
|
|
if (view.superview == nil) {
|
|
|
|
|
[self.middleContainer addSubview:view];
|
|
|
|
|
[view mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
|
|
make.center.mas_equalTo(self.middleContainer);
|
|
|
|
|
make.width.mas_equalTo(KScreenWidth);
|
|
|
|
|
make.height.mas_equalTo(KScreenHeight);
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
view.hidden = NO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma mark - Lazy init
|
|
|
|
|
- (XPRoomAnimationHitView *)bottomContainer {
|
|
|
|
|
if (!_bottomContainer) {
|
|
|
|
|
_bottomContainer = [[XPRoomAnimationHitView alloc] init];
|
|
|
|
|
}
|
|
|
|
|
return _bottomContainer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (XPRoomAnimationHitView *)middleContainer {
|
|
|
|
|
if (!_middleContainer) {
|
|
|
|
|
_middleContainer = [[XPRoomAnimationHitView alloc] init];
|
|
|
|
|
}
|
|
|
|
|
return _middleContainer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (XPRoomAnimationHitView *)topContainer {
|
|
|
|
|
if (!_topContainer) {
|
|
|
|
|
_topContainer = [[XPRoomAnimationHitView alloc] init];
|
|
|
|
|
}
|
|
|
|
|
return _topContainer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (XPRoomAnimationHitView *)bannerContainer {
|
|
|
|
|
if (!_bannerContainer) {
|
|
|
|
|
_bannerContainer = [[XPRoomAnimationHitView alloc] init];
|
2025-08-15 19:34:25 +08:00
|
|
|
|
#if DEBUG
|
|
|
|
|
_bannerContainer.backgroundColor = [UIColor colorWithWhite:0.8 alpha:0.4];
|
|
|
|
|
#endif
|
2025-01-15 19:02:58 +08:00
|
|
|
|
}
|
|
|
|
|
return _bannerContainer;
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-15 19:34:25 +08:00
|
|
|
|
- (UIView *)bannerSwipeGestureContainer {
|
|
|
|
|
if (!_bannerSwipeGestureContainer) {
|
|
|
|
|
_bannerSwipeGestureContainer = [[UIView alloc] init];
|
|
|
|
|
_bannerSwipeGestureContainer.userInteractionEnabled = YES;
|
|
|
|
|
#if DEBUG
|
|
|
|
|
_bannerSwipeGestureContainer.backgroundColor = [UIColor colorWithRed:1 green:0 blue:0 alpha:0.4];
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
return _bannerSwipeGestureContainer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (UIView *)bannerLeftTapGestureContainer {
|
|
|
|
|
if (!_bannerLeftTapGestureContainer) {
|
|
|
|
|
_bannerLeftTapGestureContainer = [[UIView alloc] init];
|
|
|
|
|
_bannerLeftTapGestureContainer.userInteractionEnabled = YES;
|
|
|
|
|
#if DEBUG
|
|
|
|
|
_bannerLeftTapGestureContainer.backgroundColor = [UIColor colorWithRed:0 green:1 blue:0 alpha:0.4];
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
return _bannerLeftTapGestureContainer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (UIView *)bannerRightTapGestureContainer {
|
|
|
|
|
if (!_bannerRightTapGestureContainer) {
|
|
|
|
|
_bannerRightTapGestureContainer = [[UIView alloc] init];
|
|
|
|
|
_bannerRightTapGestureContainer.userInteractionEnabled = YES;
|
|
|
|
|
#if DEBUG
|
|
|
|
|
_bannerRightTapGestureContainer.backgroundColor = [UIColor colorWithRed:0 green:0 blue:1 alpha:0.4];
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
return _bannerRightTapGestureContainer;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-15 19:02:58 +08:00
|
|
|
|
- (SVGAImageView *)enterEffectView {
|
|
|
|
|
if (_enterEffectView == nil) {
|
|
|
|
|
_enterEffectView = [[SVGAImageView alloc]init];
|
|
|
|
|
_enterEffectView.delegate = self;
|
2025-02-28 19:04:09 +08:00
|
|
|
|
_enterEffectView.contentMode = UIViewContentModeScaleAspectFill;
|
2025-01-15 19:02:58 +08:00
|
|
|
|
_enterEffectView.frame = CGRectMake(0, 0, KScreenWidth, 50);
|
|
|
|
|
_enterEffectView.backgroundColor = [UIColor clearColor];
|
|
|
|
|
_enterEffectView.alpha = 0;
|
|
|
|
|
_enterEffectView.userInteractionEnabled = NO;
|
|
|
|
|
}
|
|
|
|
|
return _enterEffectView;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSMutableArray *)svgaQueue{
|
|
|
|
|
if(!_svgaQueue){
|
|
|
|
|
_svgaQueue = [NSMutableArray array];
|
|
|
|
|
}
|
|
|
|
|
return _svgaQueue;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-24 16:09:48 +08:00
|
|
|
|
- (void)addToSvgaQueue:(GiftReceiveInfoModel *)model {
|
|
|
|
|
dispatch_async(self.giftEffectsQueue, ^{
|
|
|
|
|
[self.svgaQueue addObject:model];
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)removeFromSvgaQueueAtIndex:(NSInteger)index {
|
|
|
|
|
dispatch_async(self.giftEffectsQueue, ^{
|
|
|
|
|
if (index < self.svgaQueue.count) {
|
2025-06-16 17:30:20 +08:00
|
|
|
|
if (index < self.svgaQueue.count) {
|
|
|
|
|
[self.svgaQueue xpSafeRemoveObjectAtIndex:index];
|
|
|
|
|
}
|
2025-03-24 16:09:48 +08:00
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-15 19:02:58 +08:00
|
|
|
|
- (XPRoomGiftAnimationParser *)vapParser {
|
|
|
|
|
if (!_vapParser) {
|
|
|
|
|
_vapParser = [[XPRoomGiftAnimationParser alloc] init];
|
|
|
|
|
}
|
|
|
|
|
return _vapParser;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (PAGView *)pagGiftEffectView{
|
|
|
|
|
if(!_pagGiftEffectView){
|
|
|
|
|
_pagGiftEffectView = [[PAGView alloc]init];
|
|
|
|
|
[_pagGiftEffectView addListener:self];
|
|
|
|
|
_pagGiftEffectView.backgroundColor = [UIColor clearColor];
|
|
|
|
|
_pagGiftEffectView.userInteractionEnabled = NO;
|
|
|
|
|
_pagGiftEffectView.repeatCount = 1;
|
|
|
|
|
_pagGiftEffectView.scaleMode = PAGScaleModeStretch;
|
|
|
|
|
}
|
|
|
|
|
return _pagGiftEffectView;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (VAPView *)vapGiftEffectView {
|
|
|
|
|
if (!_vapGiftEffectView) {
|
|
|
|
|
_vapGiftEffectView = [[VAPView alloc] initWithFrame:CGRectMake(0, 0, KScreenWidth, KScreenHeight)];
|
|
|
|
|
_vapGiftEffectView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.5];
|
|
|
|
|
_vapGiftEffectView.contentMode = UIViewContentModeScaleAspectFill;
|
|
|
|
|
_vapGiftEffectView.hidden = YES;
|
|
|
|
|
_vapGiftEffectView.userInteractionEnabled = NO;
|
|
|
|
|
}
|
|
|
|
|
return _vapGiftEffectView;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (SVGAParser *)vggParser {
|
|
|
|
|
if (!_vggParser) {
|
|
|
|
|
_vggParser = [[SVGAParser alloc] init];
|
|
|
|
|
}
|
|
|
|
|
return _vggParser;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (SVGAImageView *)vggGiftEffectView {
|
|
|
|
|
if (!_vggGiftEffectView) {
|
|
|
|
|
_vggGiftEffectView = [[SVGAImageView alloc]init];
|
|
|
|
|
_vggGiftEffectView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.5];
|
|
|
|
|
_vggGiftEffectView.userInteractionEnabled = NO;
|
|
|
|
|
_vggGiftEffectView.delegate = self;
|
|
|
|
|
_vggGiftEffectView.hidden = YES;
|
|
|
|
|
_vggGiftEffectView.loops = 1;
|
|
|
|
|
_vggGiftEffectView.clearsAfterStop = YES;
|
|
|
|
|
}
|
|
|
|
|
return _vggGiftEffectView;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (VAPView *)carVapEffectView {
|
|
|
|
|
if (!_carVapEffectView) {
|
|
|
|
|
_carVapEffectView = [[VAPView alloc] initWithFrame:CGRectMake(0, 0, KScreenWidth, KScreenHeight)];
|
|
|
|
|
_carVapEffectView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.3];
|
|
|
|
|
_carVapEffectView.contentMode = UIViewContentModeScaleAspectFill;
|
|
|
|
|
_carVapEffectView.hidden = YES;
|
|
|
|
|
}
|
|
|
|
|
return _carVapEffectView;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (SVGAImageView *)carSVGAEffectView {
|
|
|
|
|
if (_carSVGAEffectView == nil) {
|
|
|
|
|
_carSVGAEffectView = [[SVGAImageView alloc]init];
|
|
|
|
|
_carSVGAEffectView.delegate = self;
|
|
|
|
|
_carSVGAEffectView.contentMode = UIViewContentModeScaleAspectFit;
|
|
|
|
|
_carSVGAEffectView.frame = CGRectMake(0, 0, KScreenWidth, KScreenHeight);
|
|
|
|
|
_carSVGAEffectView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.3];
|
|
|
|
|
_carSVGAEffectView.hidden = YES;
|
|
|
|
|
_carSVGAEffectView.userInteractionEnabled = NO;
|
|
|
|
|
_carSVGAEffectView.loops = 1;
|
|
|
|
|
_carSVGAEffectView.clearsAfterStop = YES;
|
|
|
|
|
}
|
|
|
|
|
return _carSVGAEffectView;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (PAGView *)carPagEffectView{
|
|
|
|
|
if(!_carPagEffectView){
|
|
|
|
|
_carPagEffectView = [[PAGView alloc]init];
|
|
|
|
|
[_carPagEffectView addListener:self];
|
|
|
|
|
_carPagEffectView.backgroundColor = [UIColor clearColor];
|
|
|
|
|
_carPagEffectView.userInteractionEnabled = NO;
|
|
|
|
|
_carPagEffectView.repeatCount = 1;
|
|
|
|
|
_carPagEffectView.scaleMode = PAGScaleModeStretch;
|
|
|
|
|
}
|
|
|
|
|
return _carPagEffectView;
|
2025-01-14 14:29:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-01-16 16:00:12 +08:00
|
|
|
|
#pragma mark - OLD METHODs
|
|
|
|
|
|
2025-08-12 13:53:12 +08:00
|
|
|
|
|
|
|
|
|
|
2025-01-16 16:00:12 +08:00
|
|
|
|
|
|
|
|
|
- (void)receiveLuckyGiftBigPrize:(AttachmentModel *)attachment {
|
|
|
|
|
if ([self _isInSudGame]) {return;}
|
|
|
|
|
|
|
|
|
|
PIBaseAnimationViewModel * prizeModel = [PIBaseAnimationViewModel modelWithDictionary:attachment.data];
|
|
|
|
|
prizeModel.type = GiftBannerType_Lucky;
|
|
|
|
|
prizeModel.isInRoomVisable = attachment.second == Custom_Message_Sub_Room_Gift_LuckBag;
|
|
|
|
|
|
|
|
|
|
if(self.animationListB.count == 0 && self.isPlayOfB == NO){
|
|
|
|
|
[self createBigPrizeAnimation:prizeModel];
|
|
|
|
|
}
|
|
|
|
|
[self.animationListB addObject:prizeModel];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)createBigPrizeAnimation:(PIBaseAnimationViewModel *)prizeModel {
|
|
|
|
|
self.isPlayOfB = YES;
|
|
|
|
|
CGFloat top = (kNavigationHeight + 15);
|
|
|
|
|
XPRoomLuckyBigPrizeView * luckyGiftEffectView = [[XPRoomLuckyBigPrizeView alloc] initWithFrame:CGRectMake(KScreenWidth, top, 375, 71)];
|
|
|
|
|
luckyGiftEffectView.delegate = self;
|
|
|
|
|
[self.topContainer addSubview:luckyGiftEffectView];
|
|
|
|
|
luckyGiftEffectView.giftInfo = prizeModel;
|
|
|
|
|
|
|
|
|
|
POPSpringAnimation *springAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPViewCenter];
|
|
|
|
|
springAnimation.springSpeed = 12;
|
|
|
|
|
springAnimation.springBounciness = 10.f;
|
|
|
|
|
springAnimation.fromValue = [NSValue valueWithCGPoint:luckyGiftEffectView.center];
|
|
|
|
|
springAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(KScreenWidth / 2, luckyGiftEffectView.center.y)];
|
|
|
|
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 7 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
|
|
|
|
|
POPBasicAnimation *moveAnimation = [POPBasicAnimation animationWithPropertyNamed:kPOPViewCenter];
|
|
|
|
|
moveAnimation.fromValue = [NSValue valueWithCGPoint:CGPointMake(0, luckyGiftEffectView.center.y)];
|
|
|
|
|
moveAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(-KScreenWidth/2, luckyGiftEffectView.center.y)];
|
|
|
|
|
moveAnimation.beginTime = CACurrentMediaTime();
|
|
|
|
|
moveAnimation.duration = 0.5;
|
|
|
|
|
moveAnimation.repeatCount = 1;
|
|
|
|
|
moveAnimation.removedOnCompletion = YES;
|
|
|
|
|
@kWeakify(self);
|
|
|
|
|
[moveAnimation setCompletionBlock:^(POPAnimation *anim, BOOL finished) {
|
|
|
|
|
@kStrongify(self);
|
|
|
|
|
if (finished) {
|
|
|
|
|
[luckyGiftEffectView removeFromSuperview];
|
|
|
|
|
if (self.animationListB.count > 0) {
|
2025-06-16 17:30:20 +08:00
|
|
|
|
[self.animationListB xpSafeRemoveObjectAtIndex:0];
|
2025-01-16 16:00:12 +08:00
|
|
|
|
}
|
|
|
|
|
self.isPlayOfB = NO;
|
|
|
|
|
[self playAnimationWithModel];
|
|
|
|
|
}
|
|
|
|
|
}];
|
|
|
|
|
[luckyGiftEffectView pop_addAnimation:moveAnimation forKey:@"moveOutAnimation"];
|
|
|
|
|
});
|
|
|
|
|
[luckyGiftEffectView pop_addAnimation:springAnimation forKey:@"nobleLevelUpspingOutAnimation"];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)receiveCandyTreeGiftHighLevle:(AttachmentModel *)attatchment {
|
|
|
|
|
if ([self _isInSudGame]) {return;}
|
|
|
|
|
PIBaseAnimationViewModel *giftModel = [PIBaseAnimationViewModel new];
|
|
|
|
|
giftModel.data = attatchment.data;
|
|
|
|
|
giftModel.second = attatchment.second;
|
|
|
|
|
giftModel.first = attatchment.first;
|
|
|
|
|
giftModel.type = GiftBannerType_Love;
|
|
|
|
|
if (self.animationListB.count == 0 && self.isPlayOfB == NO) {
|
|
|
|
|
[self createCandyTreeBannerAnimation:giftModel];
|
|
|
|
|
}
|
|
|
|
|
[self.animationListB addObject:giftModel];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)createCandyTreeBannerAnimation:(PIBaseAnimationViewModel *)attatchment {
|
|
|
|
|
CGFloat kscale = (CGFloat)60 / (CGFloat)375;
|
|
|
|
|
self.isPlayOfB = YES;
|
|
|
|
|
CGFloat top = (kNavigationHeight + 15);
|
|
|
|
|
XPRoomCandyGiftView *candyTreeView = [[XPRoomCandyGiftView alloc] initWithFrame:CGRectMake(KScreenWidth, top, KScreenWidth , KScreenWidth * kscale)];
|
|
|
|
|
candyTreeView.isMaxLargeGift = attatchment.second == Custom_Message_Sub_Look_Love_InRoom_NeedAllMicSend;
|
|
|
|
|
candyTreeView.candyInfo = attatchment.data;
|
|
|
|
|
[self.middleContainer addSubview:candyTreeView];
|
|
|
|
|
POPSpringAnimation *springAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPViewCenter];
|
|
|
|
|
springAnimation.springSpeed = 12;
|
|
|
|
|
springAnimation.springBounciness = 10.f;
|
|
|
|
|
springAnimation.fromValue = [NSValue valueWithCGPoint:candyTreeView.center];
|
|
|
|
|
springAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(candyTreeView.frame.size.width / 2, candyTreeView.center.y)];
|
|
|
|
|
@kWeakify(self);
|
|
|
|
|
[springAnimation setCompletionBlock:^(POPAnimation *anim, BOOL finished) {
|
|
|
|
|
@kStrongify(self);
|
|
|
|
|
if (finished) {
|
|
|
|
|
POPBasicAnimation *moveAnimation = [POPBasicAnimation animationWithPropertyNamed:kPOPViewCenter];
|
|
|
|
|
moveAnimation.fromValue = [NSValue valueWithCGPoint:CGPointMake(0, candyTreeView.center.y)];
|
|
|
|
|
moveAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(-KScreenWidth/2, candyTreeView.center.y)];
|
|
|
|
|
moveAnimation.beginTime = CACurrentMediaTime() + 3;
|
|
|
|
|
moveAnimation.duration = 0.5;
|
|
|
|
|
moveAnimation.repeatCount = 1;
|
|
|
|
|
moveAnimation.removedOnCompletion = YES;
|
|
|
|
|
@kWeakify(self);
|
|
|
|
|
[moveAnimation setCompletionBlock:^(POPAnimation *anim, BOOL finished) {
|
|
|
|
|
@kStrongify(self);
|
|
|
|
|
if (finished) {
|
|
|
|
|
[candyTreeView removeFromSuperview];
|
|
|
|
|
self.isPlayOfB = NO;
|
|
|
|
|
if (self.animationListB.count > 0) {
|
2025-06-16 17:30:20 +08:00
|
|
|
|
[self.animationListB xpSafeRemoveObjectAtIndex:0];
|
2025-01-16 16:00:12 +08:00
|
|
|
|
}
|
|
|
|
|
[self playAnimationWithModel];
|
|
|
|
|
}
|
|
|
|
|
}];
|
|
|
|
|
[candyTreeView pop_addAnimation:moveAnimation forKey:@"moveOutAnimation"];
|
|
|
|
|
}
|
|
|
|
|
}];
|
|
|
|
|
[candyTreeView pop_addAnimation:springAnimation forKey:@"candyTreespingOutAnimation"];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)receiveNobleLevelUp:(AttachmentModel *)attachment {
|
|
|
|
|
@kWeakify(self);
|
|
|
|
|
[[NetImageView new]loadImageWithUrl:attachment.data[@"avatar"] completion:^(UIImage * _Nonnull image, NSURL * _Nonnull url) {
|
|
|
|
|
@kStrongify(self);
|
|
|
|
|
PIBaseAnimationViewModel *nobleModel = [PIBaseAnimationViewModel new];
|
|
|
|
|
nobleModel.data = attachment.data;
|
|
|
|
|
nobleModel.type = GiftBannerType_Nobleman;
|
|
|
|
|
if (self.animationListB.count == 0 && self.isPlayOfB == NO) {
|
|
|
|
|
[self createNobleLevelUpBannerAnimation:nobleModel];
|
|
|
|
|
}
|
|
|
|
|
[self.animationListB addObject:nobleModel];
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)createNobleLevelUpBannerAnimation:(PIBaseAnimationViewModel *)model {
|
|
|
|
|
self.isPlayOfB = YES;
|
|
|
|
|
CGFloat top = (kNavigationHeight + 15);
|
|
|
|
|
XPRoomNobleLevelUpView *nobleLevelUpView = [[XPRoomNobleLevelUpView alloc] initWithFrame:CGRectMake(KScreenWidth, top, KScreenWidth, 90)];
|
|
|
|
|
nobleLevelUpView.nobleInfo = model.data;
|
|
|
|
|
[self.topContainer addSubview:nobleLevelUpView];
|
|
|
|
|
@kWeakify(self);
|
|
|
|
|
@kWeakify(nobleLevelUpView);
|
|
|
|
|
nobleLevelUpView.completionBlock = ^{
|
|
|
|
|
@kStrongify(self);
|
|
|
|
|
@kStrongify(nobleLevelUpView);
|
|
|
|
|
POPSpringAnimation *springAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPViewCenter];
|
|
|
|
|
springAnimation.springSpeed = 12;
|
|
|
|
|
springAnimation.springBounciness = 10.f;
|
|
|
|
|
springAnimation.fromValue = [NSValue valueWithCGPoint:nobleLevelUpView.center];
|
|
|
|
|
springAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(nobleLevelUpView.frame.size.width / 2, nobleLevelUpView.center.y)];
|
|
|
|
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(6.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
|
|
|
|
POPBasicAnimation *moveAnimation = [POPBasicAnimation animationWithPropertyNamed:kPOPViewCenter];
|
|
|
|
|
moveAnimation.fromValue = [NSValue valueWithCGPoint:CGPointMake(0, nobleLevelUpView.center.y)];
|
|
|
|
|
moveAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(-KScreenWidth/2, nobleLevelUpView.center.y)];
|
|
|
|
|
moveAnimation.beginTime = CACurrentMediaTime() + 3;
|
|
|
|
|
moveAnimation.duration = 0.5;
|
|
|
|
|
moveAnimation.repeatCount = 1;
|
|
|
|
|
moveAnimation.removedOnCompletion = YES;
|
|
|
|
|
@kWeakify(self);
|
|
|
|
|
[moveAnimation setCompletionBlock:^(POPAnimation *anim, BOOL finished) {
|
|
|
|
|
@kStrongify(self);
|
|
|
|
|
if (finished) {
|
|
|
|
|
self.isPlayOfB = NO;
|
|
|
|
|
[nobleLevelUpView removeFromSuperview];
|
|
|
|
|
if (self.animationListB.count > 0) {
|
2025-06-16 17:30:20 +08:00
|
|
|
|
[self.animationListB xpSafeRemoveObjectAtIndex:0];
|
2025-01-16 16:00:12 +08:00
|
|
|
|
}
|
|
|
|
|
[self playAnimationWithModel];
|
|
|
|
|
}
|
|
|
|
|
}];
|
|
|
|
|
[nobleLevelUpView pop_addAnimation:moveAnimation forKey:@"moveOutAnimation"];
|
|
|
|
|
});
|
|
|
|
|
[nobleLevelUpView pop_addAnimation:springAnimation forKey:@"nobleLevelUpspingOutAnimation"];
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)createAnchorHourRankAnimation:(PIBaseAnimationViewModel *)attachment {
|
|
|
|
|
self.isPlayOfB = YES;
|
|
|
|
|
CGFloat top = (kNavigationHeight + 15);
|
|
|
|
|
XPRoomAnchorRankBannerView *anchorRankView = [[XPRoomAnchorRankBannerView alloc] initWithFrame:CGRectMake(KScreenWidth,top, KScreenWidth, kGetScaleWidth(55))];
|
|
|
|
|
anchorRankView.anchorRankInfo = [RoomHalfHourRankModel modelWithDictionary:attachment.data];
|
|
|
|
|
anchorRankView.delegate = self;
|
|
|
|
|
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(gotoTopRankAnchorRoom:)];
|
|
|
|
|
[anchorRankView addGestureRecognizer:tap];
|
|
|
|
|
[self.topContainer addSubview:anchorRankView];
|
|
|
|
|
POPSpringAnimation *springAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPViewCenter];
|
|
|
|
|
springAnimation.springSpeed = 12;
|
|
|
|
|
springAnimation.springBounciness = 10.f;
|
|
|
|
|
springAnimation.fromValue = [NSValue valueWithCGPoint:anchorRankView.center];
|
|
|
|
|
springAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(anchorRankView.frame.size.width / 2, anchorRankView.center.y)];
|
|
|
|
|
[springAnimation setCompletionBlock:^(POPAnimation *anim, BOOL finished) {
|
|
|
|
|
if (finished) {
|
|
|
|
|
POPBasicAnimation *moveAnimation = [POPBasicAnimation animationWithPropertyNamed:kPOPViewCenter];
|
|
|
|
|
moveAnimation.fromValue = [NSValue valueWithCGPoint:CGPointMake(0, anchorRankView.center.y)];
|
|
|
|
|
moveAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(-KScreenWidth/2, anchorRankView.center.y)];
|
|
|
|
|
moveAnimation.beginTime = CACurrentMediaTime() + 3;
|
|
|
|
|
moveAnimation.duration = 0.5;
|
|
|
|
|
moveAnimation.repeatCount = 1;
|
|
|
|
|
moveAnimation.removedOnCompletion = YES;
|
|
|
|
|
[moveAnimation setCompletionBlock:^(POPAnimation *anim, BOOL finished) {
|
|
|
|
|
[anchorRankView removeFromSuperview];
|
|
|
|
|
self.isPlayOfB = NO;
|
|
|
|
|
if(self.animationListB.count > 0){
|
2025-06-16 17:30:20 +08:00
|
|
|
|
[self.animationListB xpSafeRemoveObjectAtIndex:0];
|
2025-01-16 16:00:12 +08:00
|
|
|
|
[self playAnimationWithModel];
|
|
|
|
|
}
|
|
|
|
|
}];
|
|
|
|
|
[anchorRankView pop_addAnimation:moveAnimation forKey:@"moveOutAnimation"];
|
|
|
|
|
}
|
|
|
|
|
}];
|
|
|
|
|
[anchorRankView pop_addAnimation:springAnimation forKey:@"nobleLevelUpspingOutAnimation"];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)gotoTopRankAnchorRoom:(UITapGestureRecognizer *)tap {
|
|
|
|
|
XPRoomAnchorRankBannerView * view = (XPRoomAnchorRankBannerView *)tap.view;
|
|
|
|
|
if (view.anchorRankInfo.uid.integerValue > 0) {
|
|
|
|
|
[self.hostDelegate exitRoom];
|
|
|
|
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
|
|
|
|
[XPRoomViewController openRoom:view.anchorRankInfo.uid viewController:[XCCurrentVCStackManager shareManager].getCurrentVC];
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)receiveTreasureFairyGiftHighLevel:(AttachmentModel *)attatchment {
|
|
|
|
|
if ([self _isInSudGame]) {return;}
|
|
|
|
|
PIBaseAnimationViewModel *giftModel = [PIBaseAnimationViewModel new];
|
|
|
|
|
giftModel.data = attatchment.data;
|
|
|
|
|
giftModel.second = attatchment.second;
|
|
|
|
|
giftModel.first = attatchment.first;
|
|
|
|
|
giftModel.type = GiftBannerType_Fairy;
|
|
|
|
|
if (self.animationListB.count == 0 && self.isPlayOfB == NO) {
|
|
|
|
|
[self createTreasureFairyBannerAnimation:giftModel];
|
|
|
|
|
}
|
|
|
|
|
[self.animationListB addObject:giftModel];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)createTreasureFairyBannerAnimation:(PIBaseAnimationViewModel *)attatchment {
|
|
|
|
|
self.isPlayOfB = YES;
|
|
|
|
|
CGFloat kscale = (CGFloat)60 / (CGFloat)375;
|
|
|
|
|
CGFloat top = (kNavigationHeight + 15);
|
|
|
|
|
XPTreasureFairyGiftView *treasureView = [[XPTreasureFairyGiftView alloc] initWithFrame:CGRectMake(KScreenWidth, top, KScreenWidth , KScreenWidth * kscale)];
|
|
|
|
|
//最大礼物
|
|
|
|
|
if ((attatchment.second == Custom_Message_Sub_Treasure_Fairy_Draw_Gift_L5) || (attatchment.second == Custom_Message_Sub_Treasure_Fairy_Convert_L3)) {
|
|
|
|
|
treasureView.isMaxLargeGift = YES;
|
|
|
|
|
}else{
|
|
|
|
|
treasureView.isMaxLargeGift = NO;
|
|
|
|
|
}
|
|
|
|
|
if ((attatchment.second == Custom_Message_Sub_Treasure_Fairy_Draw_Gift_L4) || (attatchment.second == Custom_Message_Sub_Treasure_Fairy_Draw_Gift_L5)) {
|
|
|
|
|
treasureView.isDrawGift = YES; //抽奖
|
|
|
|
|
}else{
|
|
|
|
|
treasureView.isDrawGift = NO; //召唤
|
|
|
|
|
}
|
|
|
|
|
treasureView.treasureInfo = attatchment.data;
|
|
|
|
|
[self.middleContainer addSubview:treasureView];
|
|
|
|
|
POPSpringAnimation *springAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPViewCenter];
|
|
|
|
|
springAnimation.springSpeed = 12;
|
|
|
|
|
springAnimation.springBounciness = 10.f;
|
|
|
|
|
springAnimation.fromValue = [NSValue valueWithCGPoint:treasureView.center];
|
|
|
|
|
springAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(treasureView.frame.size.width / 2, treasureView.center.y)];
|
|
|
|
|
[springAnimation setCompletionBlock:^(POPAnimation *anim, BOOL finished) {
|
|
|
|
|
if (finished) {
|
|
|
|
|
POPBasicAnimation *moveAnimation = [POPBasicAnimation animationWithPropertyNamed:kPOPViewCenter];
|
|
|
|
|
moveAnimation.fromValue = [NSValue valueWithCGPoint:CGPointMake(0, treasureView.center.y)];
|
|
|
|
|
moveAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(-KScreenWidth/2, treasureView.center.y)];
|
|
|
|
|
moveAnimation.beginTime = CACurrentMediaTime() + 3;
|
|
|
|
|
moveAnimation.duration = 0.5;
|
|
|
|
|
moveAnimation.repeatCount = 1;
|
|
|
|
|
moveAnimation.removedOnCompletion = YES;
|
|
|
|
|
@kWeakify(self);
|
|
|
|
|
[moveAnimation setCompletionBlock:^(POPAnimation *anim, BOOL finished) {
|
|
|
|
|
@kStrongify(self);
|
|
|
|
|
if (finished) {
|
|
|
|
|
[treasureView removeFromSuperview];
|
|
|
|
|
self.isPlayOfB = NO;
|
|
|
|
|
if (self.animationListB.count > 0) {
|
2025-06-16 17:30:20 +08:00
|
|
|
|
[self.animationListB xpSafeRemoveObjectAtIndex:0];
|
2025-01-16 16:00:12 +08:00
|
|
|
|
}
|
|
|
|
|
[self playAnimationWithModel];
|
|
|
|
|
}
|
|
|
|
|
}];
|
|
|
|
|
[treasureView pop_addAnimation:moveAnimation forKey:@"moveOutAnimation"];
|
|
|
|
|
}
|
|
|
|
|
}];
|
|
|
|
|
[treasureView pop_addAnimation:springAnimation forKey:@"candyTreespingOutAnimation"];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2025-08-12 13:53:12 +08:00
|
|
|
|
|
|
|
|
|
|
2025-01-16 16:00:12 +08:00
|
|
|
|
|
|
|
|
|
- (void)createGiftCompoundBannerAnimation:(PIBaseAnimationViewModel *)attachment {
|
|
|
|
|
self.isPlayOfB = YES;
|
|
|
|
|
XPRoomGiftCompoundView *compoundGiftView = [[XPRoomGiftCompoundView alloc] initWithFrame:CGRectMake(KScreenWidth, kNavigationHeight + 15, KScreenWidth, 45)];
|
|
|
|
|
compoundGiftView.compoundGiftInfo = attachment.data;
|
|
|
|
|
[self.middleContainer addSubview:compoundGiftView];
|
|
|
|
|
POPSpringAnimation *springAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPViewCenter];
|
|
|
|
|
springAnimation.springSpeed = 12;
|
|
|
|
|
springAnimation.springBounciness = 10.f;
|
|
|
|
|
springAnimation.fromValue = [NSValue valueWithCGPoint:compoundGiftView.center];
|
|
|
|
|
springAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(compoundGiftView.frame.size.width / 2, compoundGiftView.center.y)];
|
|
|
|
|
[springAnimation setCompletionBlock:^(POPAnimation *anim, BOOL finished) {
|
|
|
|
|
if (finished) {
|
|
|
|
|
POPBasicAnimation *moveAnimation = [POPBasicAnimation animationWithPropertyNamed:kPOPViewCenter];
|
|
|
|
|
moveAnimation.fromValue = [NSValue valueWithCGPoint:CGPointMake(0, compoundGiftView.center.y)];
|
|
|
|
|
moveAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(-KScreenWidth/2, compoundGiftView.center.y)];
|
|
|
|
|
moveAnimation.beginTime = CACurrentMediaTime() + 3;
|
|
|
|
|
moveAnimation.duration = 0.5;
|
|
|
|
|
moveAnimation.repeatCount = 1;
|
|
|
|
|
moveAnimation.removedOnCompletion = YES;
|
|
|
|
|
@kWeakify(self);
|
|
|
|
|
[moveAnimation setCompletionBlock:^(POPAnimation *anim, BOOL finished) {
|
|
|
|
|
@kStrongify(self);
|
|
|
|
|
if (finished) {
|
|
|
|
|
[compoundGiftView removeFromSuperview];
|
|
|
|
|
self.isPlayOfB = NO;
|
|
|
|
|
if(self.animationListB.count > 0){
|
2025-06-16 17:30:20 +08:00
|
|
|
|
[self.animationListB xpSafeRemoveObjectAtIndex:0];
|
2025-01-16 16:00:12 +08:00
|
|
|
|
}
|
|
|
|
|
[self playAnimationWithModel];
|
|
|
|
|
}
|
|
|
|
|
}];
|
|
|
|
|
[compoundGiftView pop_addAnimation:moveAnimation forKey:@"moveOutAnimation"];
|
|
|
|
|
}
|
|
|
|
|
}];
|
|
|
|
|
[compoundGiftView pop_addAnimation:springAnimation forKey:@"compoundGiftSpingOutAnimation"];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)createGeneralFloatingScreenAnimation:(PIBaseAnimationViewModel *)attachment bannerModel:(PIUniversalBannerModel *)model {
|
|
|
|
|
self.isPlayOfB = YES;
|
|
|
|
|
CGFloat top = (kNavigationHeight + 15);
|
|
|
|
|
|
|
|
|
|
if (!model) {
|
|
|
|
|
model = [PIUniversalBannerModel modelWithDictionary:attachment.data];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL isSvga = [model.resourceType.uppercaseString isEqualToString:@"SVGA"];
|
|
|
|
|
__block PIUniversalBannerView *bannerView;
|
|
|
|
|
@kWeakify(self);
|
|
|
|
|
if (isSvga == YES) {
|
|
|
|
|
SVGAParser *parser = [SVGAParser new];
|
|
|
|
|
[parser parseWithURL:[NSURL URLWithString:model.resourceContent] completionBlock:^(SVGAVideoEntity * _Nonnull videoItem) {
|
|
|
|
|
@kStrongify(self);
|
|
|
|
|
model.videoItem = videoItem;
|
|
|
|
|
CGFloat height = kGetScaleWidth(60);
|
|
|
|
|
if(videoItem.videoSize.width > 0){
|
|
|
|
|
height = KScreenWidth * videoItem.videoSize.height / videoItem.videoSize.width;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bannerView = [[PIUniversalBannerView alloc]initWithFrame:CGRectMake(KScreenWidth, top, KScreenWidth, height)];
|
|
|
|
|
[self showGeneralFloatingScreenView:bannerView model:model];
|
|
|
|
|
} failureBlock:^(NSError * _Nonnull error) {
|
|
|
|
|
@kStrongify(self);
|
|
|
|
|
[bannerView removeFromSuperview];
|
|
|
|
|
self.isPlayOfB = NO;
|
|
|
|
|
if(self.animationListB.count > 0){
|
2025-06-16 17:30:20 +08:00
|
|
|
|
[self.animationListB xpSafeRemoveObjectAtIndex:0];
|
2025-01-16 16:00:12 +08:00
|
|
|
|
}
|
|
|
|
|
[self playAnimationWithModel];
|
|
|
|
|
}];
|
|
|
|
|
}else{
|
|
|
|
|
if (!_imageLoader) {
|
|
|
|
|
_imageLoader = [[NetImageView alloc] init];
|
|
|
|
|
}
|
|
|
|
|
[self.imageLoader loadImageWithUrl:model.resourceContent
|
|
|
|
|
completion:^(UIImage * _Nonnull image, NSURL * _Nonnull url) {
|
|
|
|
|
@kStrongify(self);
|
|
|
|
|
model.image = image;
|
|
|
|
|
CGFloat width = image.size.width <= 0 ? kGetScaleWidth(60) : image.size.width;
|
|
|
|
|
CGFloat height = image.size.height ;
|
|
|
|
|
CGFloat getHeight = KScreenWidth * height / width;
|
|
|
|
|
if (getHeight > 100) {
|
|
|
|
|
getHeight = 100;
|
|
|
|
|
}
|
|
|
|
|
bannerView = [[PIUniversalBannerView alloc]initWithFrame:CGRectMake(KScreenWidth, top, KScreenWidth, getHeight) ];
|
|
|
|
|
[self showGeneralFloatingScreenView:bannerView model:model];
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
fail:^(NSError * _Nonnull error) {
|
|
|
|
|
@kStrongify(self);
|
|
|
|
|
[bannerView removeFromSuperview];
|
|
|
|
|
self.isPlayOfB = NO;
|
|
|
|
|
if(self.animationListB.count > 0){
|
2025-06-16 17:30:20 +08:00
|
|
|
|
[self.animationListB xpSafeRemoveObjectAtIndex:0];
|
2025-01-16 16:00:12 +08:00
|
|
|
|
}
|
|
|
|
|
[self playAnimationWithModel];
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
-(void)showGeneralFloatingScreenView:(PIUniversalBannerView *)bannerView model:(PIUniversalBannerModel *)model{
|
|
|
|
|
BOOL isSvga = [model.resourceType isEqualToString:@"SVGA"];
|
|
|
|
|
bannerView.isSvga = isSvga;
|
|
|
|
|
bannerView.delegate = self;
|
2025-03-24 16:09:48 +08:00
|
|
|
|
if (!_universalBannerViewCaches) {
|
|
|
|
|
_universalBannerViewCaches = @[].mutableCopy;
|
|
|
|
|
}
|
|
|
|
|
[self.universalBannerViewCaches addObject:bannerView];
|
2025-02-28 19:04:09 +08:00
|
|
|
|
@kWeakify(bannerView);
|
2025-01-16 16:00:12 +08:00
|
|
|
|
@kWeakify(self);
|
2025-02-28 19:04:09 +08:00
|
|
|
|
[bannerView setAllowToPlay:^{
|
|
|
|
|
@kStrongify(self);
|
|
|
|
|
@kStrongify(bannerView);
|
|
|
|
|
[self.topContainer addSubview:bannerView];
|
|
|
|
|
POPSpringAnimation *springAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPViewCenter];
|
|
|
|
|
springAnimation.springSpeed = 12;
|
|
|
|
|
springAnimation.springBounciness = 10.f;
|
|
|
|
|
springAnimation.fromValue = [NSValue valueWithCGPoint:bannerView.center];
|
|
|
|
|
springAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(bannerView.frame.size.width / 2, bannerView.center.y)];
|
|
|
|
|
@kWeakify(self);
|
|
|
|
|
[springAnimation setCompletionBlock:^(POPAnimation *anim, BOOL finished) {
|
|
|
|
|
if (finished) {
|
|
|
|
|
POPBasicAnimation *moveAnimation = [POPBasicAnimation animationWithPropertyNamed:kPOPViewCenter];
|
|
|
|
|
moveAnimation.fromValue = [NSValue valueWithCGPoint:CGPointMake(0, bannerView.center.y)];
|
|
|
|
|
moveAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(-KScreenWidth/2, bannerView.center.y)];
|
|
|
|
|
moveAnimation.beginTime = CACurrentMediaTime() + 5;
|
|
|
|
|
moveAnimation.duration = 0.5;
|
|
|
|
|
moveAnimation.repeatCount = 1;
|
|
|
|
|
moveAnimation.removedOnCompletion = YES;
|
|
|
|
|
|
|
|
|
|
[moveAnimation setCompletionBlock:^(POPAnimation *anim, BOOL finished) {
|
|
|
|
|
@kStrongify(self);
|
|
|
|
|
if (finished) {
|
|
|
|
|
[bannerView removeFromSuperview];
|
2025-03-24 16:09:48 +08:00
|
|
|
|
[self.universalBannerViewCaches removeObject:bannerView];
|
2025-02-28 19:04:09 +08:00
|
|
|
|
self.isPlayOfB = NO;
|
|
|
|
|
if(self.animationListB.count > 0){
|
2025-06-16 17:30:20 +08:00
|
|
|
|
[self.animationListB xpSafeRemoveObjectAtIndex:0];
|
2025-02-28 19:04:09 +08:00
|
|
|
|
}
|
|
|
|
|
[self playAnimationWithModel];
|
2025-01-16 16:00:12 +08:00
|
|
|
|
}
|
2025-02-28 19:04:09 +08:00
|
|
|
|
}];
|
|
|
|
|
[bannerView pop_addAnimation:moveAnimation forKey:@"moveOutAnimation"];
|
|
|
|
|
}
|
|
|
|
|
}];
|
|
|
|
|
[bannerView pop_addAnimation:springAnimation forKey:@"starKitchenOutAnimation"];
|
2025-01-16 16:00:12 +08:00
|
|
|
|
}];
|
2025-02-28 19:04:09 +08:00
|
|
|
|
|
|
|
|
|
bannerView.model = model;
|
2025-01-16 16:00:12 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)roomDatingPublicResult:(AttachmentModel *)attachment {
|
|
|
|
|
self.datingEffectQueue = [NSMutableArray array];
|
|
|
|
|
///心动结果公布的话 结果是一个数组
|
|
|
|
|
NSArray * results = [DatingInfoModel modelsWithArray:attachment.data[@"list"]];
|
|
|
|
|
[self.datingEffectQueue addObjectsFromArray:results];
|
|
|
|
|
if (self.datingEffectQueue.count > 0) {
|
|
|
|
|
[self startDatingAnimation:self.datingEffectQueue.firstObject];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)startDatingAnimation:(DatingInfoModel *)datingModel {
|
|
|
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:@"message" object:[self createRoomDatingResultMessage:datingModel]];
|
|
|
|
|
NSString * targetUid= [NSString stringWithFormat:@"%ld", datingModel.targetUid];
|
|
|
|
|
NSString * uid= [NSString stringWithFormat:@"%ld", datingModel.uid];
|
|
|
|
|
if (datingModel.hasHeart || datingModel.hasSelectUser) {
|
|
|
|
|
datingModel.originPoint = [self.hostDelegate animationPointAtStageViewByUid:uid];
|
|
|
|
|
datingModel.targetPoint = [self.hostDelegate animationPointAtStageViewByUid:targetUid];
|
|
|
|
|
}
|
|
|
|
|
XPRoomDatingAnimationView *datingView = [[XPRoomDatingAnimationView alloc] init];
|
|
|
|
|
[self.topContainer addSubview:datingView];
|
|
|
|
|
[datingView startAnimationWithModel:datingModel finishBlock:^(BOOL finish) {
|
|
|
|
|
[datingView removeFromSuperview];
|
|
|
|
|
[self.datingEffectQueue removeObject:datingModel];
|
|
|
|
|
if (self.datingEffectQueue.count > 0) {
|
|
|
|
|
DatingInfoModel * datingModel = [self.datingEffectQueue firstObject];
|
|
|
|
|
[self startDatingAnimation:datingModel];
|
|
|
|
|
}
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NIMMessage *)createRoomDatingResultMessage:(DatingInfoModel *)datingModel {
|
|
|
|
|
NIMMessage * message = [[NIMMessage alloc] init];
|
|
|
|
|
NIMSession * session = [NIMSession session:[NSString stringWithFormat:@"%ld", self.hostDelegate.getRoomInfo.roomId] type:NIMSessionTypeChatroom];
|
|
|
|
|
[message setValue:session forKey:@"session"];
|
|
|
|
|
AttachmentModel * attach = [[AttachmentModel alloc] init];
|
|
|
|
|
attach.first = CustomMessageType_RoomPlay_Dating;
|
|
|
|
|
if (datingModel.hasHeart) {///如果是互选的话
|
|
|
|
|
attach.second = Custom_Message_Sub_Room_Play_Dating_Result_Mutual;
|
|
|
|
|
} else {
|
|
|
|
|
attach.second = Custom_Message_Sub_Room_Play_Dating_Result_Not_Mutual;
|
|
|
|
|
}
|
|
|
|
|
attach.data = [datingModel model2dictionary];
|
|
|
|
|
NIMCustomObject * object = [[NIMCustomObject alloc] init];
|
|
|
|
|
object.attachment = attach;
|
|
|
|
|
message.messageObject = object;
|
|
|
|
|
return message;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)acrossRoomPKBannerAnimation:(AttachmentModel *)attacment {
|
|
|
|
|
AcrossRoomPKPrizeModel * prizeModel = [AcrossRoomPKPrizeModel modelWithJSON:attacment.data];
|
|
|
|
|
if (attacment.second == Custom_Message_Sub_AnchorPK_Result) {
|
|
|
|
|
prizeModel.pkType = 1;
|
|
|
|
|
} else {
|
|
|
|
|
prizeModel.pkType = 0;
|
|
|
|
|
}
|
|
|
|
|
[self.acrossRoomPKQueue addObject:prizeModel];
|
|
|
|
|
if (self.acrossRoomPKQueue.count == 1 ) {//判断为1个时开始播放,防止多条消息回来后重叠播放
|
|
|
|
|
[self startAcrossRoomPKAnimation:self.acrossRoomPKQueue.firstObject];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)startAcrossRoomPKAnimation:(AcrossRoomPKPrizeModel *)model {
|
|
|
|
|
XPAcrossRoomPKPrizeView *wishEffectView = [[XPAcrossRoomPKPrizeView alloc] initWithFrame:CGRectMake(KScreenWidth, kNavigationHeight+40, KScreenWidth, 87)];
|
|
|
|
|
wishEffectView.data = model;
|
|
|
|
|
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(gotoPkWinRoom:)];
|
|
|
|
|
[wishEffectView addGestureRecognizer:tap];
|
|
|
|
|
[self.topContainer addSubview:wishEffectView];
|
|
|
|
|
[UIView animateWithDuration:0.5 animations:^{
|
|
|
|
|
wishEffectView.frame = CGRectMake(0, kNavigationHeight+40, KScreenWidth, 87);
|
|
|
|
|
} completion:^(BOOL finished) {
|
|
|
|
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
|
|
|
|
[UIView animateWithDuration:0.5 animations:^{
|
|
|
|
|
wishEffectView.hidden = YES;
|
|
|
|
|
} completion:^(BOOL finished) {
|
|
|
|
|
[wishEffectView removeFromSuperview];
|
|
|
|
|
[self.acrossRoomPKQueue removeObject:model];
|
|
|
|
|
if (self.acrossRoomPKQueue.count > 0) {
|
|
|
|
|
[self startAcrossRoomPKAnimation:self.acrossRoomPKQueue.firstObject];
|
|
|
|
|
}
|
|
|
|
|
}];
|
|
|
|
|
});
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)gotoPkWinRoom:(UITapGestureRecognizer *)tap {
|
|
|
|
|
XPAcrossRoomPKPrizeView * view = (XPAcrossRoomPKPrizeView *)tap.view;
|
|
|
|
|
if (view.data.winUid.length > 0) {
|
|
|
|
|
[self.hostDelegate exitRoom];
|
|
|
|
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
|
|
|
|
[XPRoomViewController openRoom:view.data.winUid viewController:[XCCurrentVCStackManager shareManager].getCurrentVC];
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)receiveFansTeamGiftHandleSendGiftAnimation:(AttachmentModel *)attachment {
|
|
|
|
|
if ([self _isInSudGame]) {return;}
|
|
|
|
|
if (!self.hostDelegate.getRoomInfo.hasAnimationEffect) {return;}
|
|
|
|
|
GiftReceiveInfoModel *receiveInfo = [[GiftReceiveInfoModel alloc] init];
|
|
|
|
|
GiftInfoModel *gift = [GiftInfoModel modelWithJSON:attachment.data[@"giftVo"]];
|
|
|
|
|
receiveInfo.gift = gift;
|
|
|
|
|
receiveInfo.giftInfo = gift;
|
|
|
|
|
receiveInfo.targetUid = [NSString stringWithFormat:@"%ld", self.hostDelegate.getRoomInfo.uid];
|
|
|
|
|
GiftInfoModel * giftInfo = receiveInfo.gift ? receiveInfo.gift : receiveInfo.giftInfo;
|
|
|
|
|
if (attachment.second == Custom_Message_Sub_AllMicroLuckySend || attachment.second == Custom_Message_Sub_AllBatchMicroLuckySend || attachment.second == Custom_Message_Sub_Gift_LuckySend) {
|
|
|
|
|
NSString * giftId = [NSString stringWithFormat:@"%ld", receiveInfo.luckyGiftList.giftList.firstObject.giftId];
|
2025-03-06 15:26:44 +08:00
|
|
|
|
giftInfo = [[XPGiftStorage shareStorage] findGiftInfo:giftId inRoom:@(receiveInfo.roomUid).stringValue];
|
2025-01-16 16:00:12 +08:00
|
|
|
|
}
|
|
|
|
|
if (giftInfo == nil) {
|
2025-03-06 15:26:44 +08:00
|
|
|
|
giftInfo = [[XPGiftStorage shareStorage] findGiftInfo:receiveInfo.giftId inRoom:@(receiveInfo.roomUid).stringValue];
|
2025-01-16 16:00:12 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///在最外面判断是否可以拿到那个礼物 后面使用就不用判断了
|
|
|
|
|
receiveInfo.gift = giftInfo;
|
|
|
|
|
receiveInfo.isLuckyBagGift = (attachment.second == Custom_Message_Sub_AllMicroLuckySend || attachment.second == Custom_Message_Sub_AllBatchMicroLuckySend || attachment.second == Custom_Message_Sub_Gift_LuckySend);
|
|
|
|
|
[self.giftAnimationManager enqueueGift:receiveInfo];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)receiveAnchorHourRank:(AttachmentModel *)attachment {
|
|
|
|
|
PIBaseAnimationViewModel *anchorModel =[PIBaseAnimationViewModel new];
|
|
|
|
|
anchorModel.data = attachment.data;
|
|
|
|
|
anchorModel.type = GiftBannerType_AnchorHour;
|
|
|
|
|
if(self.animationListB.count == 0 && self.isPlayOfB == NO){
|
|
|
|
|
[self createAnchorHourRankAnimation:anchorModel];
|
|
|
|
|
}
|
|
|
|
|
[self.animationListB addObject:anchorModel];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)receiveGiftCompound:(AttachmentModel *)attachment {
|
|
|
|
|
if ([self _isInSudGame]) {return;}
|
|
|
|
|
PIBaseAnimationViewModel *magicModel =[PIBaseAnimationViewModel new];
|
|
|
|
|
magicModel.data = attachment.data;
|
|
|
|
|
magicModel.type = GiftBannerType_Magic_House;
|
|
|
|
|
if(self.animationListB.count == 0 && self.isPlayOfB == NO){
|
|
|
|
|
[self createGiftCompoundBannerAnimation:magicModel];
|
|
|
|
|
}
|
|
|
|
|
[self.animationListB addObject:magicModel];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)receiveRoomSailing:(AttachmentModel *)attachment {
|
|
|
|
|
if ([self _isInSudGame]) {return;}
|
|
|
|
|
if (self.sailingQueue.count == 0) {
|
|
|
|
|
[self createSailingBannerAnimation:attachment];
|
|
|
|
|
}
|
|
|
|
|
[self.sailingQueue addObject:attachment];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)createSailingBannerAnimation:(AttachmentModel *)attatchment {
|
|
|
|
|
CGFloat kscale = (CGFloat)60 / (CGFloat)375;
|
|
|
|
|
XPSailingAnimationView *sailingView = [[XPSailingAnimationView alloc] initWithFrame:CGRectMake(KScreenWidth, kNavigationHeight + 15, KScreenWidth, KScreenWidth * kscale)];
|
|
|
|
|
sailingView.prizeInfo = attatchment.data;
|
|
|
|
|
[self.middleContainer addSubview:sailingView];
|
|
|
|
|
POPSpringAnimation *springAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPViewCenter];
|
|
|
|
|
springAnimation.springSpeed = 12;
|
|
|
|
|
springAnimation.springBounciness = 10.f;
|
|
|
|
|
springAnimation.fromValue = [NSValue valueWithCGPoint:sailingView.center];
|
|
|
|
|
springAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(sailingView.frame.size.width / 2, sailingView.center.y)];
|
|
|
|
|
[springAnimation setCompletionBlock:^(POPAnimation *anim, BOOL finished) {
|
|
|
|
|
if (finished) {
|
|
|
|
|
POPBasicAnimation *moveAnimation = [POPBasicAnimation animationWithPropertyNamed:kPOPViewCenter];
|
|
|
|
|
moveAnimation.fromValue = [NSValue valueWithCGPoint:CGPointMake(0, sailingView.center.y)];
|
|
|
|
|
moveAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(-KScreenWidth/2, sailingView.center.y)];
|
|
|
|
|
moveAnimation.beginTime = CACurrentMediaTime() + 3;
|
|
|
|
|
moveAnimation.duration = 0.5;
|
|
|
|
|
moveAnimation.repeatCount = 1;
|
|
|
|
|
moveAnimation.removedOnCompletion = YES;
|
|
|
|
|
@kWeakify(self);
|
|
|
|
|
[moveAnimation setCompletionBlock:^(POPAnimation *anim, BOOL finished) {
|
|
|
|
|
@kStrongify(self);
|
|
|
|
|
if (finished) {
|
|
|
|
|
[sailingView removeFromSuperview];
|
|
|
|
|
if (self.sailingQueue.count > 0) {
|
2025-06-16 17:30:20 +08:00
|
|
|
|
[self.sailingQueue xpSafeRemoveObjectAtIndex:0];
|
2025-01-16 16:00:12 +08:00
|
|
|
|
}
|
|
|
|
|
if (self.sailingQueue.count > 0) {
|
|
|
|
|
[self createSailingBannerAnimation:self.sailingQueue.firstObject];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}];
|
|
|
|
|
[sailingView pop_addAnimation:moveAnimation forKey:@"moveOutAnimation"];
|
|
|
|
|
}
|
|
|
|
|
}];
|
|
|
|
|
[sailingView pop_addAnimation:springAnimation forKey:@"candyTreespingOutAnimation"];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)receiveRoomGraffitiGift:(AttachmentModel *)attachment {
|
|
|
|
|
if (self.graffitiGiftQueue.count == 0) {
|
|
|
|
|
[self startGraffitiGiftAnimation:attachment];
|
|
|
|
|
}
|
|
|
|
|
[self.graffitiGiftQueue addObject:attachment];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)startGraffitiGiftAnimation:(AttachmentModel *)model {
|
|
|
|
|
NSDictionary * dic = model.data;
|
|
|
|
|
NSNumber * giftId = dic[@"giftId"];
|
2025-03-06 15:26:44 +08:00
|
|
|
|
GiftInfoModel * giftInfo = [[XPGiftStorage shareStorage] findGiftInfo:giftId.stringValue inRoom:@""];
|
2025-01-16 16:00:12 +08:00
|
|
|
|
NSArray * array = dic[@"drawFixedArray"];
|
|
|
|
|
if (giftInfo.giftUrl.length > 0 && array.count > 0) {
|
|
|
|
|
[[SDWebImageManager sharedManager] loadImageWithURL:[NSURL URLWithString:giftInfo.giftUrl] options:SDWebImageProgressiveLoad progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
|
|
|
|
|
if (error == nil && image) {
|
|
|
|
|
XPRoomGraffitiGiftAnimationView *graffitiView = [[XPRoomGraffitiGiftAnimationView alloc] initWithFrame:CGRectMake(0, 0, KScreenWidth, KScreenHeight)];
|
|
|
|
|
graffitiView.giftImage = image;
|
|
|
|
|
graffitiView.delegate = self;
|
|
|
|
|
graffitiView.model = model;
|
|
|
|
|
graffitiView.pointArray = array;
|
|
|
|
|
[graffitiView beginDrawAnimation];
|
|
|
|
|
[self.topContainer addSubview:graffitiView];
|
|
|
|
|
} else {
|
|
|
|
|
[self.graffitiGiftQueue removeObject:model];
|
|
|
|
|
if (self.graffitiGiftQueue.count > 0) {
|
|
|
|
|
[self startGraffitiGiftAnimation:self.graffitiGiftQueue.firstObject];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}];
|
|
|
|
|
} else {
|
|
|
|
|
[self.graffitiGiftQueue removeObject:model];
|
|
|
|
|
if (self.graffitiGiftQueue.count > 0) {
|
|
|
|
|
[self startGraffitiGiftAnimation:self.graffitiGiftQueue.firstObject];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)playLuckyGiftEffectWithVapUrl:(NSString *)vapUrl {
|
|
|
|
|
NSString *encodingUrl = [vapUrl pureURLString];
|
|
|
|
|
encodingUrl = [encodingUrl stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
|
|
|
|
|
NSString *fileName = [[encodingUrl componentsSeparatedByString:@"/"] lastObject];
|
|
|
|
|
NSString *fullPath = [self.GiftDynamicEffectListPath stringByAppendingPathComponent:fileName];
|
|
|
|
|
|
|
|
|
|
if ([[NSFileManager defaultManager] fileExistsAtPath:fullPath]){
|
|
|
|
|
vapUrl = fullPath;
|
|
|
|
|
[self _addSubviewToMiddleContainer:self.luckyVapGiftEffectView];
|
|
|
|
|
[self.luckyVapGiftEffectView setMute:NO];
|
|
|
|
|
[self.luckyVapGiftEffectView playHWDMP4:vapUrl repeatCount:1 delegate:self];
|
|
|
|
|
} else {
|
|
|
|
|
@kWeakify(self);
|
|
|
|
|
[self.vapParser parseWithURL:encodingUrl completionBlock:^(NSString * _Nullable videoUrl) {
|
|
|
|
|
@kStrongify(self);
|
|
|
|
|
if (videoUrl.length) {
|
|
|
|
|
[self _addSubviewToMiddleContainer:self.luckyVapGiftEffectView];
|
|
|
|
|
[self.luckyVapGiftEffectView setMute:NO];
|
|
|
|
|
[self.luckyVapGiftEffectView playHWDMP4:videoUrl repeatCount:1 delegate:self];
|
|
|
|
|
}
|
|
|
|
|
} failureBlock:^(NSError * _Nullable error) {
|
|
|
|
|
self.luckyVapGiftEffectView.hidden = YES;
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
-(void)playAnimationWithModel{
|
|
|
|
|
if(self.animationListB.count <= 0){
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(self.isPlayOfB == YES) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PIBaseAnimationViewModel *model = self.animationListB.firstObject;
|
2025-08-12 14:51:13 +08:00
|
|
|
|
switch (model.type) {
|
|
|
|
|
case GiftBannerType_Lucky:
|
|
|
|
|
[self createBigPrizeAnimation:model];
|
|
|
|
|
break;
|
|
|
|
|
case GiftBannerType_Love:
|
|
|
|
|
[self createCandyTreeBannerAnimation:model];
|
|
|
|
|
break;
|
|
|
|
|
case GiftBannerType_Nobleman:
|
|
|
|
|
[self createNobleLevelUpBannerAnimation:model];
|
|
|
|
|
break;
|
|
|
|
|
case GiftBannerType_AnchorHour:
|
|
|
|
|
[self createAnchorHourRankAnimation:model];
|
|
|
|
|
break;
|
|
|
|
|
case GiftBannerType_LicneseHour:
|
|
|
|
|
[self createAnchorHourRankAnimation:model];
|
|
|
|
|
break;
|
|
|
|
|
case GiftBannerType_Fairy:
|
|
|
|
|
[self createTreasureFairyBannerAnimation:model];
|
|
|
|
|
break;
|
|
|
|
|
case GiftBannerType_Magic_House:
|
|
|
|
|
[self createGiftCompoundBannerAnimation:model];
|
|
|
|
|
break;
|
|
|
|
|
case GiftBannerType_General_Floating_Screen:
|
|
|
|
|
[self createGeneralFloatingScreenAnimation:model bannerModel:nil];
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
// 其他未处理的枚举值类型
|
|
|
|
|
// 可能包括但不限于:GiftBannerType_Unknown, GiftBannerType_Normal,
|
|
|
|
|
// GiftBannerType_Special, GiftBannerType_Event 等
|
|
|
|
|
break;
|
2025-01-16 16:00:12 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (SVGAImageView *)luckyGiftEffectView {
|
|
|
|
|
if (!_luckyGiftEffectView) {
|
|
|
|
|
_luckyGiftEffectView = [[SVGAImageView alloc]init];
|
|
|
|
|
_luckyGiftEffectView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.5];
|
|
|
|
|
_luckyGiftEffectView.userInteractionEnabled = NO;
|
|
|
|
|
_luckyGiftEffectView.delegate = self;
|
|
|
|
|
_luckyGiftEffectView.hidden = YES;
|
|
|
|
|
}
|
|
|
|
|
return _luckyGiftEffectView;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (VAPView *)luckyVapGiftEffectView {
|
|
|
|
|
if (!_luckyVapGiftEffectView) {
|
|
|
|
|
_luckyVapGiftEffectView = [[VAPView alloc] initWithFrame:CGRectMake(0, 0, KScreenWidth, KScreenHeight)];
|
|
|
|
|
_luckyVapGiftEffectView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.5];
|
|
|
|
|
_luckyVapGiftEffectView.contentMode = UIViewContentModeScaleAspectFill;
|
|
|
|
|
_luckyVapGiftEffectView.hidden = YES;
|
|
|
|
|
}
|
|
|
|
|
return _luckyVapGiftEffectView;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma mark - Old Methods Delegate: XPRoomGiftBroadcastViewDelegate
|
|
|
|
|
- (void)xPRoomGiftBroadcastView:(XPRoomGiftBroadcastView *)view enterRoom:(NSString *)roomUid roomName:(NSString *)roomName{
|
|
|
|
|
id isShowBroadcastView = [[NSUserDefaults standardUserDefaults]valueForKey:@"kSaveBrooadcastSelectState"];
|
|
|
|
|
if(isShowBroadcastView == nil){
|
|
|
|
|
PIRoomGiftBroadcastWindow *broadcastView = [[PIRoomGiftBroadcastWindow alloc] initWithFrame:CGRectMake(0, 0, KScreenWidth, KScreenHeight)];
|
|
|
|
|
broadcastView.roodUid = roomUid;
|
|
|
|
|
broadcastView.roomName = roomName;
|
|
|
|
|
broadcastView.delegate = self;
|
|
|
|
|
[kWindow addSubview:broadcastView];
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (roomUid.length > 0 && self.hostDelegate.getRoomInfo.uid != roomUid.integerValue) {
|
|
|
|
|
[self.hostDelegate exitRoom];
|
|
|
|
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.7 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
|
|
|
|
[XPRoomViewController openRoom:roomUid viewController:[XCCurrentVCStackManager shareManager].getCurrentVC];
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)xPRoomLuckyBigPrizeView:(XPRoomLuckyBigPrizeView *)view luckyGiftInfo:(PIBaseAnimationViewModel *)giftInfo {
|
|
|
|
|
id isShowBroadcastView = [[NSUserDefaults standardUserDefaults]valueForKey:@"kSaveLuckSelectState"];
|
|
|
|
|
if(isShowBroadcastView == nil){
|
|
|
|
|
PIRoomGiftBroadcastWindow *broadcastView = [[PIRoomGiftBroadcastWindow alloc] initWithFrame:CGRectMake(0, 0, KScreenWidth, KScreenHeight)];
|
|
|
|
|
broadcastView.isLuck = YES;
|
|
|
|
|
broadcastView.roodUid = giftInfo.roomUid;
|
|
|
|
|
broadcastView.roomName = giftInfo.roomTitle;
|
|
|
|
|
broadcastView.delegate = self;
|
|
|
|
|
[kWindow addSubview:broadcastView];
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!giftInfo.isInRoomVisable && giftInfo.roomUid.length > 0 && giftInfo.roomUid.integerValue != self.hostDelegate.getRoomInfo.uid) {
|
|
|
|
|
[self.hostDelegate exitRoom];
|
|
|
|
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
|
|
|
|
[XPRoomViewController openRoom:giftInfo.roomUid viewController:[XCCurrentVCStackManager shareManager].getCurrentVC];
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-12 14:07:38 +08:00
|
|
|
|
|
2025-01-16 16:00:12 +08:00
|
|
|
|
|
|
|
|
|
- (void)xPRoomAnchorRankBannerView:(XPRoomAnchorRankBannerView *)view rankInfo:(RoomHalfHourRankModel *)rankInfo{
|
|
|
|
|
if (rankInfo.uid.integerValue > 0 && self.hostDelegate.getRoomInfo.uid != rankInfo.uid.integerValue) {
|
|
|
|
|
[self.hostDelegate exitRoom];
|
|
|
|
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
|
|
|
|
[XPRoomViewController openRoom:rankInfo.uid viewController:[XCCurrentVCStackManager shareManager].getCurrentVC];
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
-(void)confirmLeaveForTheRoom:(NSString *_Nonnull)roomUid{
|
|
|
|
|
if (roomUid.length > 0 && self.hostDelegate.getRoomInfo.uid != roomUid.integerValue) {
|
|
|
|
|
[self.hostDelegate exitRoom];
|
|
|
|
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.7 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
|
|
|
|
[XPRoomViewController openRoom:roomUid viewController:[XCCurrentVCStackManager shareManager].getCurrentVC];
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)pIUniversalBannerView:(PIUniversalBannerView *)view didClick:(PIUniversalBannerModel *)model{
|
|
|
|
|
if (model.skipType == 2){
|
|
|
|
|
[self.hostDelegate exitRoom];
|
|
|
|
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
|
|
|
|
[XPRoomViewController openRoom:model.skipContent viewController:[XCCurrentVCStackManager shareManager].getCurrentVC];
|
|
|
|
|
});
|
|
|
|
|
}else if (model.skipType == 3){
|
|
|
|
|
XPWebViewController * webVC = [[XPWebViewController alloc] initWithRoomUID:nil];
|
|
|
|
|
webVC.isPush = YES;
|
|
|
|
|
webVC.url = model.skipContent;
|
|
|
|
|
[self.hostDelegate.getCurrentNav pushViewController:webVC animated:YES];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)xPRoomGraffitiGiftAnimationViewCompletion:(XPRoomGraffitiGiftAnimationView *)view attachment:(nonnull AttachmentModel *)attachment{
|
|
|
|
|
[view removeFromSuperview];
|
|
|
|
|
if ([self.graffitiGiftQueue containsObject:attachment]) {
|
|
|
|
|
[self.graffitiGiftQueue removeObject:attachment];
|
|
|
|
|
}
|
|
|
|
|
if (self.graffitiGiftQueue.count > 0) {
|
|
|
|
|
[self startGraffitiGiftAnimation:self.graffitiGiftQueue.firstObject];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-15 11:41:45 +08:00
|
|
|
|
#pragma mark - Touch Event Handling
|
|
|
|
|
|
2025-08-15 19:34:25 +08:00
|
|
|
|
// 移除pointInside重写,让触摸事件正常传递
|
|
|
|
|
|
|
|
|
|
#pragma mark - Public Methods
|
|
|
|
|
|
|
|
|
|
- (CGPoint)getSavedTapPoint {
|
|
|
|
|
return self.savedTapPoint;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL)hasSavedTapPointAvailable {
|
|
|
|
|
return self.hasSavedTapPoint;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)clearSavedTapPoint {
|
|
|
|
|
self.hasSavedTapPoint = NO;
|
|
|
|
|
self.savedTapPoint = CGPointZero;
|
2025-08-15 11:41:45 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-01-14 14:29:14 +08:00
|
|
|
|
@end
|