Files
peko-ios/YuMi/Modules/YMRoom/View/AnimationView/GiftAnimationManager.m
2025-01-13 15:29:58 +08:00

239 lines
7.2 KiB
Objective-C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// GiftAnimationManager.m
// YuMi
//
// Created by P on 2024/12/9.
//
#import "GiftAnimationManager.h"
#import "GiftComboManager.h"
#import "GiftAnimationHelper.h"
#import "GiftReceiveInfoModel.h"
@interface GiftAnimationManager ()
@property (nonatomic, strong) dispatch_source_t giftTimer;
@property (nonatomic, strong) dispatch_queue_t queue;
@property (nonatomic, strong) NSMutableArray<GiftReceiveInfoModel *> *giftQueue;
@property (nonatomic, strong) GiftAnimationHelper *animationHelper;
@end
@implementation GiftAnimationManager
- (void)dealloc {
if (_queue) {
_queue = NULL;
}
}
- (instancetype)initWithContainerView:(UIView *)containerView {
self = [super init];
if (self) {
_containerView = containerView;
_giftQueue = [NSMutableArray array];
_animationHelper = [[GiftAnimationHelper alloc] init];
_animationInterval = 0.2;
_comboAnimationDelay = 0.2;
_standardAnimationDelay = 0.3;
_queue = dispatch_queue_create("com.GiftAnimationManager.queue", DISPATCH_QUEUE_SERIAL);
}
return self;
}
- (void)startGiftQueue {
if (self.giftTimer) {
return;
}
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0,
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
dispatch_source_set_timer(timer,
DISPATCH_TIME_NOW,
self.animationInterval * NSEC_PER_SEC,
0.01 * NSEC_PER_SEC);
@kWeakify(self);
dispatch_source_set_event_handler(timer, ^{
@kStrongify(self);
[self processNextGift];
});
dispatch_async(dispatch_get_main_queue(), ^{
@kStrongify(self);
[self processNextGift];
});
dispatch_resume(timer);
self.giftTimer = timer;
}
- (void)processNextGift {
dispatch_async(self.queue, ^{
if (self.giftQueue.count == 0) {
[self stopGiftQueue];
return;
}
GiftReceiveInfoModel *giftInfo = self.giftQueue.firstObject;
if (!giftInfo) return;
@kWeakify(self);
dispatch_async(dispatch_get_main_queue(), ^{
@kStrongify(self);
[self distributeGiftAnimation:giftInfo];
});
// 安全地移除第一个元素
if (self.giftQueue.count > 0) {
[self.giftQueue removeObjectAtIndex:0];
}
});
}
- (void)distributeGiftAnimation:(GiftReceiveInfoModel *)giftInfo {
NSArray<NSString *> *targetUids = [self resolveTargetUids:giftInfo];
CGPoint startPoint = CGPointZero;
BOOL isComboAnimation = [self shouldUseComboAnimationForSender:giftInfo.uid];
if (isComboAnimation) {
startPoint = [self comboAnimationStartPoint];
} else {
[self calculateAnimationPoint:giftInfo.uid isEndPoint:NO];
}
NSTimeInterval delay = isComboAnimation ? self.comboAnimationDelay : self.standardAnimationDelay;
for (NSString *targetUid in targetUids) {
CGPoint endPoint = [self calculateAnimationPoint:targetUid isEndPoint:YES];
[self scheduleAnimationWithDelay:delay
giftInfo:giftInfo.gift
startPoint:startPoint
endPoint:endPoint
isComboAnimation:isComboAnimation];
}
}
- (NSArray<NSString *> *)resolveTargetUids:(GiftReceiveInfoModel *)giftInfo {
if (!giftInfo) {
return @[];
}
if (giftInfo.isLuckyBagGift) {
return @[giftInfo.targetUid];
}
if (giftInfo.targetUids.count > 0) {
return [giftInfo.targetUids valueForKey:@"stringValue"];
}
if (giftInfo.targetUsers) {
NSArray *uidDatas = [self ensureArrayContainsOnlyStrings:[giftInfo.targetUsers valueForKeyPath:@"uid"]];
return uidDatas;//[giftInfo.targetUsers valueForKeyPath:@"uid"];
}
return [NSString isEmpty:giftInfo.targetUid] ? @[] : @[giftInfo.targetUid];
}
- (NSArray<NSString *> *)ensureArrayContainsOnlyStrings:(NSArray *)inputArray {
// 用于存放最终结果
NSMutableArray<NSString *> *resultArray = [NSMutableArray array];
for (id item in inputArray) {
if ([item isKindOfClass:[NSString class]]) {
// 如果是 NSString直接添加到结果数组
[resultArray addObject:item];
} else if ([item isKindOfClass:[NSNumber class]]) {
// 如果是 NSNumber转换为 NSString 后添加
[resultArray addObject:[item stringValue]];
} else {
// 对于非 NSString 或 NSNumber 的类型,可以选择忽略或者抛出异常
NSLog(@"Warning: Unsupported item type: %@", [item class]);
}
}
return [resultArray copy]; // 返回不可变数组
}
- (CGPoint)calculateAnimationPoint:(NSString *)uid isEndPoint:(BOOL)isEndPoint {
if (uid.length == 0) {
return [self fallbackPointForEndPoint:isEndPoint];
}
CGPoint point = [self.delegate animationPointAtStageViewByUid:uid];
if (!CGPointEqualToPoint(point, CGPointZero)) {
return point;
}
return [self fallbackPointForEndPoint:isEndPoint];
}
- (void)scheduleAnimationWithDelay:(NSTimeInterval)delay
giftInfo:(GiftInfoModel *)giftInfo
startPoint:(CGPoint)startPoint
endPoint:(CGPoint)endPoint
isComboAnimation:(BOOL)isComboAnimation {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, delay * NSEC_PER_SEC),
dispatch_get_main_queue(), ^{
[self.animationHelper beginGiftAnimation:giftInfo.giftUrl
startPoint:startPoint
endPoint:endPoint
isGiftCombing:isComboAnimation
toTargetView:self.containerView];
});
}
- (void)stopGiftQueue {
if (self.giftTimer) {
// 取消定时器
dispatch_source_cancel(self.giftTimer);
// 设置取消回调,在资源完全释放后将 timer 置为 nil
dispatch_source_set_cancel_handler(self.giftTimer, ^{
self.giftTimer = nil;
});
}
}
- (void)enqueueGift:(GiftReceiveInfoModel *)giftInfo {
if (!giftInfo) {
return;
}
dispatch_async(self.queue, ^{
[self.giftQueue addObject:giftInfo];
[self startGiftQueue];
});
}
// Helper methods
- (BOOL)shouldUseComboAnimationForSender:(NSString *)uid {
return [[GiftComboManager sharedManager] isGiftCombing] &&
[uid isEqualToString:[AccountInfoStorage instance].getUid];
}
- (CGPoint)fallbackPointForEndPoint:(BOOL)isEndPoint {
CGFloat x = [UIScreen mainScreen].bounds.size.width / 2;
if (isEndPoint) {
x += 30;
}
return CGPointMake(x, 44 + kSafeAreaTopHeight);
}
- (CGPoint)comboAnimationStartPoint {
CGFloat x = 0;
if (isMSRTL()) {
x = kGetScaleWidth(90);
} else {
x = KScreenWidth - kGetScaleWidth(90);
}
return CGPointMake(x,
KScreenHeight - kSafeAreaBottomHeight - kGetScaleWidth(140));
}
@end