418 lines
15 KiB
Objective-C
418 lines
15 KiB
Objective-C
//
|
||
// 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
|