Files
peko-ios/YuMi/Modules/YMRoom/View/AnimationView/LuckyGiftWinningBannerView.m

418 lines
15 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.

//
// LuckyGiftWinningBannerView.m
// YuMi
//
// Created by P on 2024/9/10.
//
#import "LuckyGiftWinningBannerView.h"
#import <POP.h>
#import "AttachmentModel.h"
#import "i18nGiftNameMap.h"
#import "XPRoomViewController.h"
#import "XCCurrentVCStackManager.h"
// Constants
static const CGFloat kBannerWidth = 346.5f;
static const CGFloat kBannerHeight = 55.0;
static const CGFloat kBannerTopMargin = 0;// 80.0f;
//static const CGFloat kAvatarSize = 43.0f;
//static const CGFloat kAnimationDuration = 0.25f;
//static const CGFloat kDisplayDuration = 2.0f;
//static const CGFloat kRoomTransitionDelay = 2.0f;
@interface LuckyGiftWinningBannerViewModel : PIBaseModel
@property (nonatomic, copy, readonly) NSString *times;
@property (nonatomic, copy, readonly) NSString *avatar;
@property (nonatomic, copy, readonly) NSString *coins;
@property (nonatomic, copy, readonly) NSDictionary *giftNameMap;
@property (nonatomic, copy, readonly) NSString *roomUid;
@property (nonatomic, copy, readonly) NSString *giftName;
@end
@implementation LuckyGiftWinningBannerViewModel
+ (NSDictionary *)replacedKeyFromPropertyName {
return @{@"avatar": @"sender.avatar"};
}
- (NSString *)giftName {
if (isMSRTL() && [self.giftNameMap[@"ar"] length]) {
return self.giftNameMap[@"ar"];
}
if (isMSZH() && [self.giftNameMap[@"zh"] length]) {
return self.giftNameMap[@"zh"];
}
return self.giftNameMap[@"en"] ?: @"";
}
@end
@interface LuckyGiftWinningBannerView ()
@property (nonatomic, strong) LuckyGiftWinningBannerViewModel *model;
@property (nonatomic, strong) UIImageView *backgroundImageView;
@property (nonatomic, strong) UIImageView *ballImageView;
@property (nonatomic, strong) UIImageView *bigBallImageView;
@property (nonatomic, strong) NetImageView *avatarImageView;
@property (nonatomic, strong) UILabel *giftNameLabel;
@property (nonatomic, strong) UILabel *timesLabel;
@property (nonatomic, strong) UILabel *coinsLabel;
@property (nonatomic, assign) NSInteger currentRoomUid;
@property (nonatomic, copy) void(^completeDisplay)(void);
@property (nonatomic, copy) void(^exitCurrentRoom)(void);
@property (nonatomic, assign) BOOL isAnimationCancelled;
@end
@implementation LuckyGiftWinningBannerView
- (void)dealloc
{
}
+ (void)display:(UIView *)superView
inRoomUid:(NSInteger)roomUid
with:(AttachmentModel *)attachment
complete:(void(^)(void))complete
exitCurrentRoom:(void(^)(void))exit {
#if DEBUG
NSParameterAssert(superView);
NSParameterAssert(attachment);
#else
if (!superView || !attachment) {
if (complete) {
complete();
}
return;
}
#endif
LuckyGiftWinningBannerViewModel *model = [LuckyGiftWinningBannerViewModel modelWithDictionary:attachment.data];
CGFloat width = KScreenWidth;//kGetScaleWidth(kBannerWidth);
CGFloat height = kBannerHeight;// kGetScaleWidth(kBannerHeight);
CGRect frame = CGRectMake(KScreenWidth, kBannerTopMargin, width, height);
LuckyGiftWinningBannerView *bannerView = [[LuckyGiftWinningBannerView alloc] initWithFrame:frame];
bannerView.model = model;
bannerView.completeDisplay = complete;
bannerView.exitCurrentRoom = exit;
bannerView.currentRoomUid = roomUid;
[superView addSubview:bannerView];
NSInteger time = 3;
@kWeakify(bannerView);
[bannerView popEnterAnimation:^(BOOL finished) {
@kStrongify(bannerView);
[bannerView addNotification];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(time * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[bannerView popLeaveAnimation:^(bool finished) {
if (bannerView.completeDisplay) {
bannerView.completeDisplay();
}
[bannerView removeNotification];
[bannerView removeFromSuperview];
}];
});
}];
}
- (void)handleSwipeNotification {
[self dismissBanner];
}
- (void)handleTapNotification:(NSNotification *)note {
NSValue *value = note.userInfo[@"point"];
CGPoint point = [value CGPointValue];
// 计算中央 2/3 区域
CGFloat totalW = KScreenWidth;
CGFloat regionW = totalW * 2.0 / 3.0;
CGFloat originX = (totalW - regionW) / 2.0;
CGRect centerRegion = CGRectMake(originX,
0, // 高度不做限制就填 0
regionW,
self.bounds.size.height);
if (CGRectContainsPoint(centerRegion, point)) {
NSLog(@" Banner tap 点落在中央 2/3 区域");
[self handelTap];
} else {
NSLog(@" Banner tap 点不落在中央 2/3 区域");
// 将 banner 中的点转换为屏幕坐标系
CGPoint screenPoint = [self convertPoint:point toView:nil];
// 发送通知给 FunctionContainer 处理,传递屏幕坐标
[[NSNotificationCenter defaultCenter] postNotificationName:@"BannerTapToFunctionContainer"
object:nil
userInfo:@{@"point": [NSValue valueWithCGPoint:screenPoint]}];
}
}
- (void)addNotification {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleSwipeNotification)
name:@"SwipeOutBanner"
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleTapNotification:)
name:@"TapBanner"
object:nil];
}
- (void)removeNotification {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)dismissBanner {
NSLog(@"🚨 LuckyGiftWinningBannerView dismissBanner 被调用");
[self pop_removeAllAnimations]; // 停止所有动画
[self popLeaveAnimation:^(bool finished) {
NSLog(@"🚨 LuckyGiftWinningBannerView 动画完成,调用回调");
if (self.completeDisplay) {
self.completeDisplay();
} else {
NSLog(@"🚨 警告: completeDisplay 回调为空");
}
[self removeFromSuperview];
}];
}
- (void)popEnterAnimation:(void(^)(BOOL finished))finish {
POPSpringAnimation *enterAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPViewFrame];
enterAnimation.toValue = [NSValue valueWithCGRect:CGRectMake((KScreenWidth - kGetScaleWidth(kBannerWidth))/2, 0, kGetScaleWidth(kBannerWidth), kGetScaleWidth(kBannerHeight))];
enterAnimation.springBounciness = 10; // 弹性系数
enterAnimation.springSpeed = 12; // 动画速度
enterAnimation.completionBlock = ^(POPAnimation *anim, BOOL finished) {
if (finish) {
finish(finished);
}
};
[self pop_addAnimation:enterAnimation forKey:@"enterAnimation"];
}
- (void)popLeaveAnimation:(void(^)(bool finished))finish {
POPBasicAnimation *exitAnimation = [POPBasicAnimation animationWithPropertyNamed:kPOPViewFrame];
exitAnimation.toValue = [NSValue valueWithCGRect:CGRectMake(-KScreenWidth, 0, kGetScaleWidth(kBannerWidth), kGetScaleWidth(kBannerHeight))];
exitAnimation.duration = 0.25; // 动画持续时间
exitAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
exitAnimation.completionBlock = ^(POPAnimation *anim, BOOL finished) {
if (finish) {
finish(finished);
}
};
[self pop_addAnimation:exitAnimation forKey:@"exitAnimation"];
}
- (void)setModel:(LuckyGiftWinningBannerViewModel *)model {
_model = model;
self.avatarImageView.imageUrl = model.avatar;
self.giftNameLabel.text = [model giftName];
self.timesLabel.text = model.times;
self.coinsLabel.text = model.coins;
}
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self setupUI];
UIButton *b = [UIButton buttonWithType:UIButtonTypeCustom];
[self addSubview:b];
[b mas_remakeConstraints:^(MASConstraintMaker *make) {
make.edges.mas_equalTo(self);
}];
// [b addTarget:self action:@selector(handelTap) forControlEvents:UIControlEventTouchUpInside];
}
return self;
}
- (void)handelTap {
if (self.model.roomUid.integerValue == self.currentRoomUid) {
return;
}
// 在弹框显示前保存必要数据避免依赖banner对象
NSString *targetRoomUid = self.model.roomUid;
void(^exitCurrentRoomBlock)(void) = self.exitCurrentRoom;
@kWeakify(self);
[TTPopup alertWithMessage:YMLocalizedString(@"Combo_10") confirmHandler:^{
@kStrongify(self);
// 检查banner是否还存在
if (!self) {
NSLog(@"⚠️ LuckyGiftWinningBannerView: banner已被移除但弹框回调仍在执行");
// 即使banner被移除仍然执行跳转逻辑
if (exitCurrentRoomBlock) {
exitCurrentRoomBlock();
}
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[XPRoomViewController openRoom:targetRoomUid
viewController:[XCCurrentVCStackManager shareManager].getCurrentVC];
});
return;
}
// banner还存在正常执行
if (self.exitCurrentRoom) {
self.exitCurrentRoom();
}
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[XPRoomViewController openRoom:targetRoomUid
viewController:[XCCurrentVCStackManager shareManager].getCurrentVC];
});
} cancelHandler:^{}];
}
- (void)setupUI {
[self addSubview:self.backgroundImageView];
[self.backgroundImageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.mas_equalTo(self);
}];
[self addSubview:self.ballImageView];
[self.ballImageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.mas_equalTo(self);
make.trailing.mas_equalTo(self).offset(-30);
make.width.height.mas_equalTo(59);
}];
[self addSubview:self.avatarImageView];
[self.avatarImageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.mas_equalTo(self);
make.leading.mas_equalTo(kGetScaleWidth(36));
if (iPhoneXSeries) {
make.width.height.mas_equalTo(34);
} else {
make.width.height.mas_equalTo(29);
}
}];
UILabel *titleLabel_1 = [UILabel labelInitWithText:YMLocalizedString(@"Combo_0") font:kFontSemibold(14) textColor:[UIColor whiteColor]];
[self addSubview:titleLabel_1];
[titleLabel_1 mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(self.avatarImageView).offset(-3);
make.leading.mas_equalTo(self.avatarImageView.mas_trailing).offset(5);
}];
[self addSubview:self.giftNameLabel];
[self.giftNameLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.mas_equalTo(titleLabel_1);
make.leading.mas_equalTo(titleLabel_1.mas_trailing).offset(3);
}];
UILabel *titleLabel_2 = [UILabel labelInitWithText:YMLocalizedString(@"Combo_4") font:kFontSemibold(14) textColor:[UIColor whiteColor]];
[self addSubview:titleLabel_2];
[titleLabel_2 mas_makeConstraints:^(MASConstraintMaker *make) {
make.bottom.mas_equalTo(self.avatarImageView.mas_bottom);
make.leading.mas_equalTo(self.avatarImageView.mas_trailing).offset(5);
}];
[self addSubview:self.timesLabel];
[self.timesLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.mas_equalTo(titleLabel_2);
make.leading.mas_equalTo(titleLabel_2.mas_trailing).offset(3);
}];
UILabel *titleLabel_3 = [UILabel labelInitWithText:YMLocalizedString(@"Combo_9") font:kFontSemibold(14) textColor:[UIColor whiteColor]];
[self addSubview:titleLabel_3];
[titleLabel_3 mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.mas_equalTo(self.timesLabel);
make.leading.mas_equalTo(self.timesLabel.mas_trailing).offset(3);
}];
[self addSubview:self.coinsLabel];
[self.coinsLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.mas_equalTo(self.ballImageView);
make.top.mas_equalTo(self).offset(14);
make.height.mas_equalTo(22);
make.width.mas_lessThanOrEqualTo(self.ballImageView).multipliedBy(0.8);
}];
UILabel *titleLabel_4 = [UILabel labelInitWithText:YMLocalizedString(@"Combo_5") font:kFontMedium(12) textColor:[UIColor whiteColor]];
[self addSubview:titleLabel_4];
[titleLabel_4 mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.mas_equalTo(self.coinsLabel);
make.top.mas_equalTo(self.coinsLabel.mas_bottom).offset(-2);
}];
}
#pragma mark -
- (UIImageView *)backgroundImageView {
if (!_backgroundImageView) {
_backgroundImageView = [[UIImageView alloc] initWithImage:[kImage(@"luck_gift_flag") ms_SetImageForRTL]];
_backgroundImageView.contentMode = UIViewContentModeScaleAspectFit;
_backgroundImageView.alpha = 0.9;
}
return _backgroundImageView;
}
- (UIImageView *)ballImageView {
if (!_ballImageView) {
_ballImageView = [[UIImageView alloc] initWithImage:kImage(@"luck_gift_flag_ball")];
_ballImageView.contentMode = UIViewContentModeScaleAspectFill;
// _ballImageView.hidden = YES;
}
return _ballImageView;
}
- (UIImageView *)bigBallImageView {
if (!_bigBallImageView) {
_bigBallImageView = [[UIImageView alloc] initWithImage:kImage(@"luck_gift_flag_ball_BIG")];
_bigBallImageView.contentMode = UIViewContentModeScaleAspectFill;
_bigBallImageView.hidden = YES;
}
return _bigBallImageView;
}
- (NetImageView *)avatarImageView {
if (!_avatarImageView) {
NetImageConfig * config = [[NetImageConfig alloc]init];
config.placeHolder = [UIImageConstant defaultAvatarPlaceholder];
config.imageType = ImageTypeCornerAvatar;
_avatarImageView = [[NetImageView alloc] initWithConfig:config];
_avatarImageView.backgroundColor = [UIColor clearColor];
_avatarImageView.contentMode = UIViewContentModeScaleAspectFill;
[_avatarImageView setCornerRadius: iPhoneXSeries ? 34/2 : 29/2
corners:kCALayerMaxXMaxYCorner | kCALayerMaxXMinYCorner | kCALayerMinXMaxYCorner | kCALayerMinXMinYCorner
borderWidth:1
borderColor:[UIColor whiteColor]];
}
return _avatarImageView;
}
- (UILabel *)giftNameLabel {
if (!_giftNameLabel) {
_giftNameLabel = [UILabel labelInitWithText:@"" font:kFontSemibold(14) textColor:UIColorFromRGB(0xffe375)];
}
return _giftNameLabel;
}
- (UILabel *)coinsLabel {
if (!_coinsLabel) {
_coinsLabel = [UILabel labelInitWithText:@"" font:kFontSemibold(15) textColor:UIColorFromRGB(0xffe375)];
_coinsLabel.adjustsFontSizeToFitWidth = YES;
_coinsLabel.minimumScaleFactor = 0.5;
_coinsLabel.textAlignment = NSTextAlignmentCenter;
}
return _coinsLabel;
}
- (UILabel *)timesLabel {
if (!_timesLabel) {
_timesLabel = [UILabel labelInitWithText:@"" font:kFontSemibold(14) textColor:UIColorFromRGB(0xffe375)];
}
return _timesLabel;
}
@end