// // MyDressingViewController.m // YuMi // // Created by P on 2024/11/13. // #import "MyDressingViewController.h" #import #import #import "UserInfoModel.h" #import "MyDressingDataPresent.h" #import "ShoppingMallItemPreview.h" #import "XPSkillCardPlayerManager.h" #import "XPRoomGiftAnimationParser.h" #import "ShoppingMallCategoryListView.h" static NSArray *> *MyDressUpOptions(void) { return @[ @{YMLocalizedString(@"XPMineDressUpViewController2") : @1}, // 座驾 @{YMLocalizedString(@"XPMineDressUpViewController1") : @0}, // 头饰 @{YMLocalizedString(@"XPMineDressUpViewController3") : @2}, // 铭牌 @{YMLocalizedString(@"XPMineDressUpViewController4") : @3}, // 资料卡 @{YMLocalizedString(@"XPMineDressUpViewController5") : @4}, // 聊天气泡 @{YMLocalizedString(@"1.0.30_text_9") : @5} // 個人頁裝飾 ]; } @interface MyDressingViewController () @property(nonatomic, strong) UserInfoModel *userInfo; @property(nonatomic, strong) NetImageView *avatarView; @property(nonatomic, strong) NetImageView *avatarHeadViewImageView; @property(nonatomic, strong) SVGAImageView *avatarHeadWearSVGA; @property (nonatomic, strong) UIView *playEffectMask; @property (nonatomic, strong) VAPView *mp4Effect; @property(nonatomic, strong) XPRoomGiftAnimationParser *mp4Parser; @property (nonatomic, strong) SVGAImageView *svgaEffect; @property(nonatomic, strong) UIActivityIndicatorView *loading; @property(nonatomic, strong) MyDressingDataModel *selectedModel; @property(nonatomic, strong) ShoppingMallCategoryListView *listView; @end @implementation MyDressingViewController - (MyDressingDataPresent *)createPresenter { return [[MyDressingDataPresent alloc] init]; } - (BOOL)isHiddenNavBar { return YES; } - (void)viewDidLoad { [super viewDidLoad]; self.userInfo = [XPSkillCardPlayerManager shareInstance].userInfoModel; [self setupUI]; [self updateAvatar]; } - (void)setupUI { [self setupBackground]; [self setupNavigationBar]; [self setupAvatar]; [self setupContentList]; } - (void)setupBackground { self.view.backgroundColor = UIColorFromRGB(0x02061D); UIImageView *topBG = [[UIImageView alloc] initWithImage:kImage(@"mall_top_bg")]; [self.view addSubview:topBG]; [topBG mas_makeConstraints:^(MASConstraintMaker *make) { make.top.leading.trailing.mas_equalTo(self.view); make.height.mas_equalTo(kGetScaleWidth(200)); }]; } - (void)setupNavigationBar { UILabel *titleLabel = [self titleLabel]; UIButton *backButton = [self backButton]; [self.view addSubview:titleLabel]; [self.view addSubview:backButton]; [titleLabel mas_makeConstraints:^(MASConstraintMaker *make) { make.centerX.mas_equalTo(self.view); make.top.mas_equalTo(self.view).offset(44 + 11); make.height.mas_equalTo(22); }]; [backButton mas_makeConstraints:^(MASConstraintMaker *make) { make.leading.mas_equalTo(self.view).offset(16); make.centerY.mas_equalTo(titleLabel); make.size.mas_equalTo(CGSizeMake(22, 22)); }]; } - (void)setupAvatar { [self.view addSubview:self.avatarView]; [self.avatarView mas_makeConstraints:^(MASConstraintMaker *make) { make.top.mas_equalTo(100); make.centerX.mas_equalTo(self.view); make.size.mas_equalTo(CGSizeMake(kGetScaleWidth(73), kGetScaleWidth(73))); }]; [self.view addSubview:self.avatarHeadViewImageView]; [self.avatarHeadViewImageView mas_makeConstraints:^(MASConstraintMaker *make) { make.center.mas_equalTo(self.avatarView); make.size.mas_equalTo(self.avatarView).multipliedBy(1.3); }]; [self.view addSubview:self.avatarHeadWearSVGA]; [self.avatarHeadWearSVGA mas_makeConstraints:^(MASConstraintMaker *make) { make.center.mas_equalTo(self.avatarView); make.size.mas_equalTo(self.avatarView).multipliedBy(1.3); }]; } - (void)setupContentList { NSInteger bottom = kSafeAreaBottomHeight; // 内部列表使用 frame 布局,这里要计算 height ShoppingMallCategoryListView *listView = [[ShoppingMallCategoryListView alloc] initWithFrame:CGRectMake(0, 0, KScreenWidth, KScreenHeight - 100 - 73)]; listView.isForMyDressingPage = YES; listView.bottomSpace = bottom; [self.view addSubview:listView]; [listView mas_makeConstraints:^(MASConstraintMaker *make) { make.top.mas_equalTo(self.avatarView.mas_bottom).offset(16); make.leading.trailing.bottom.mas_equalTo(self.view); }]; @kWeakify(self); listView.fetchDataForMyDressingPage = ^(NSInteger pageIndex, NSInteger pageNum, FetchDataForMyDressingCompletion _Nonnull completion) { @kStrongify(self); [self fetchDataForPage:pageIndex pageNum:pageNum completion:completion]; }; listView.didTapItemPlay = ^(NSString * _Nonnull resourcePath, NSInteger effectType, NSInteger type) { @kStrongify(self); CGSize size = CGSizeZero; switch (type) { case 0: // 头饰 size = CGSizeMake(kGetScaleWidth(183), kGetScaleWidth(183)); break; case 5: size = CGSizeMake(KScreenWidth - 20, KScreenWidth - 20); break; default: size = CGSizeMake(KScreenWidth, KScreenHeight); break; } [self playItemEffect:resourcePath effectType:effectType size:size]; }; listView.returnMyDressingSelectedModel = ^(MyDressingDataModel * _Nonnull model, NSInteger type, NSIndexPath *indexPath) { @kStrongify(self); [self handTapItem:model type:type indexPath:indexPath]; }; listView.items = MyDressUpOptions(); self.listView = listView; } - (void)updateAvatar { self.avatarView.imageUrl = self.userInfo.avatar; if ([NSString isEmpty:self.userInfo.headwearEffect]) { [self.avatarHeadWearSVGA stopAnimation]; self.avatarHeadWearSVGA.hidden = YES; } else { if ([self.userInfo.headwearEffect.lowercaseString hasSuffix:@"svga"]) { self.avatarHeadWearSVGA.hidden = NO; self.avatarHeadViewImageView.hidden = YES; SVGAParser *p = [[SVGAParser alloc] init]; [p parseWithURL:[NSURL URLWithString:self.userInfo.headwearEffect] completionBlock:^(SVGAVideoEntity * _Nullable videoItem) { self.avatarHeadWearSVGA.videoItem = videoItem; [self.avatarHeadWearSVGA startAnimation]; self.avatarHeadWearSVGA.hidden = NO; } failureBlock:^(NSError * _Nullable error) {}]; } else { self.avatarHeadWearSVGA.hidden = YES; self.avatarHeadViewImageView.hidden = NO; self.avatarHeadViewImageView.imageUrl = self.userInfo.headwearEffect; } } } #pragma mark - - (void)fetchDataForPage:(NSInteger)pageIndex pageNum:(NSInteger)pageNum completion:(FetchDataForMyDressingCompletion)completion { switch (pageIndex) { case 0: { [self.presenter loadMyDressingItems:0 page:pageNum success:^(NSArray * _Nonnull array, NSInteger type) { if (completion) { completion(array); } } failure:^(NSError * _Nonnull error) { }]; } break; case 1: { [self.presenter loadVehicles:^(NSArray * _Nonnull array) { if (completion) { NSMutableArray *transArray = @[].mutableCopy; for (CarModel *car in array) { MyDressingDataModel *model = [MyDressingDataModel modelFromVehicle:car]; [transArray addObject:model]; } completion(transArray); } } failure:^(NSError * _Nonnull error) { }]; } break; case 2: { [self.presenter loadNameplate:pageNum success:^(NSArray * _Nonnull array) { if (completion) { NSMutableArray *transArray = @[].mutableCopy; for (NameplateModel *nameplate in array) { MyDressingDataModel *model = [MyDressingDataModel modelFromNameplate:nameplate]; [transArray addObject:model]; } completion(transArray); } } failure:^(NSError * _Nonnull error) { }]; } break; case 3: { [self.presenter loadRoomCard:pageNum success:^(NSArray * _Nonnull array) { if (completion) { NSMutableArray *transArray = @[].mutableCopy; for (NobleCardModel *nobleCard in array) { MyDressingDataModel *model = [MyDressingDataModel modelFromNobelCard:nobleCard]; [transArray addObject:model]; } completion(transArray); } } failure:^(NSError * _Nonnull error) { }]; } break; case 4: { [self.presenter loadBubble:pageNum success:^(NSArray * _Nonnull array) { if (completion) { NSMutableArray *transArray = @[].mutableCopy; for (ChatBubbleModel *bubble in array) { MyDressingDataModel *model = [MyDressingDataModel modelFromChatBubble:bubble]; [transArray addObject:model]; } completion(transArray); } } failure:^(NSError * _Nonnull error) { }]; } break; case 5: { [self.presenter loadMyDressingItems:5 page:pageNum success:^(NSArray * _Nonnull array, NSInteger type) { if (completion) { completion(array); } } failure:^(NSError * _Nonnull error) { }]; } break; default: break; } } - (void)handTapItem:(MyDressingDataModel *)model type:(NSInteger)type indexPath:(NSIndexPath *)indexPath { if (model.hasExpired) { // 弹窗购买 BOOL isVaild = model.obtainWay<=1; if (isVaild) { isVaild = ![NSString isEmpty:model.dressShopId] && model.dressShopId.integerValue > 0; } ShoppingMallItemPreview *preview = [[ShoppingMallItemPreview alloc] initWithMyDress:model isVaild:isVaild]; preview.frame = CGRectMake(0, 0, 284, 353); [TTPopup popupView:preview style:TTPopupStyleAlert]; @kWeakify(self); [preview setRebuyWith:^(MyDressingDataModel * _Nonnull model) { @kStrongify(self); @kWeakify(self) [self.presenter rebuyItem:model.dressShopId success:^(id _Nonnull obj) { @kStrongify(self); [TTPopup dismiss]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [self showSuccessToast:YMLocalizedString(@"XPDressUpShopListViewController0")]; [self.listView updateSelectedItem:indexPath]; }); } failure:^(NSError * _Nonnull error) { @kStrongify(self); [self showErrorToast:error.localizedDescription]; }]; }]; } else { // 直接使用 NSInteger dressID = 0; if (model) { if (type == 1 || type == 2) { dressID = model.id; } else { dressID = model.dressId.integerValue; } } @kWeakify(self); [self.presenter useDressBy:type dressID:dressID success:^(UserInfoModel *userInfo){ @kStrongify(self); if (userInfo) { self.userInfo = userInfo; [XPSkillCardPlayerManager shareInstance].userInfoModel = userInfo; [self updateAvatar]; } [self.listView updateSelectedItem:indexPath]; } failure:^(NSError * _Nonnull error) { // NSLog(@"%@", error); }]; } } #pragma mark - - (void)didTapBack { [self.navigationController popViewControllerAnimated:YES]; } #pragma mark - - (void)playItemEffect:(NSString *)path effectType:(NSInteger)effectType size:(CGSize)size { if (!_playEffectMask) { [self.view addSubview:self.playEffectMask]; [self.playEffectMask mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.mas_equalTo(self.view); }]; [self.playEffectMask addSubview:self.svgaEffect]; [self.playEffectMask addSubview:self.mp4Effect]; } [self.svgaEffect mas_updateConstraints:^(MASConstraintMaker *make) { make.center.mas_equalTo(self.playEffectMask); make.size.mas_equalTo(size); }]; [self.mp4Effect mas_updateConstraints:^(MASConstraintMaker *make) { make.center.mas_equalTo(self.playEffectMask); make.size.mas_equalTo(size); }]; self.playEffectMask.hidden = NO; [self.loading startAnimating]; if ([path.lowercaseString hasSuffix:@"mp4"] || effectType == 1) { [self playMP4:path]; } else if ([path.lowercaseString hasSuffix:@"svga"] || effectType == 2) { [self playSVGA:path]; } else { [self playSVGA:path]; } } - (void)playMP4:(NSString *)path { @kWeakify(self); [self.mp4Parser parseWithURL:path completionBlock:^(NSString * _Nullable videoUrl) { @kStrongify(self); [self.loading stopAnimating]; self.mp4Effect.hidden = NO; [self.mp4Effect playHWDMP4:videoUrl repeatCount:-1 delegate:nil]; } failureBlock:^(NSError * _Nullable error) { @kStrongify(self); [self stopItemEffect]; }]; } - (void)playSVGA:(NSString *)path { @kWeakify(self); SVGAParser *p = [[SVGAParser alloc] init]; [p parseWithURL:[NSURL URLWithString:path] completionBlock:^(SVGAVideoEntity * _Nullable videoItem) { @kStrongify(self); [self.loading stopAnimating]; self.svgaEffect.hidden = NO; self.svgaEffect.videoItem = videoItem; [self.svgaEffect startAnimation]; } failureBlock:^(NSError * _Nullable error) { @kStrongify(self); [self stopItemEffect]; }]; } - (void)stopItemEffect { [self.loading stopAnimating]; [self.svgaEffect stopAnimation]; self.svgaEffect.hidden = YES; [self.mp4Effect stopHWDMP4]; self.mp4Effect.hidden = YES; self.playEffectMask.hidden = YES; } #pragma mark - - (UIButton *)backButton { UIButton *b = [UIButton buttonWithType:UIButtonTypeCustom]; [b setImage:[kImage(@"common_nav_back_white") ms_SetImageForRTL] forState:UIControlStateNormal]; [b addTarget:self action:@selector(didTapBack) forControlEvents:UIControlEventTouchUpInside]; return b; } - (UILabel *)titleLabel { UILabel *label = [[UILabel alloc] init]; label.textAlignment = NSTextAlignmentCenter; label.font = kFontMedium(17); label.text = YMLocalizedString(@"1.0.30_text_8"); label.textColor = UIColorFromRGB(0xD9E7F7); return label; } - (UIView *)playEffectMask { if (!_playEffectMask) { _playEffectMask = [[UIView alloc] initWithFrame:self.view.bounds]; _playEffectMask.backgroundColor = [UIColor colorWithWhite:0 alpha:0.7f]; [_playEffectMask addSubview:self.loading]; [self.loading mas_makeConstraints:^(MASConstraintMaker *make) { make.center.mas_equalTo(_playEffectMask); }]; UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(stopItemEffect)]; [_playEffectMask addGestureRecognizer:tap]; } return _playEffectMask; } - (SVGAImageView *)svgaEffect { if (!_svgaEffect) { _svgaEffect = [[SVGAImageView alloc] init]; _svgaEffect.contentMode = UIViewContentModeScaleAspectFit; _svgaEffect.autoPlay = YES; _svgaEffect.loops = 0; _svgaEffect.clearsAfterStop = YES; _svgaEffect.hidden = YES; _svgaEffect.userInteractionEnabled = YES; } return _svgaEffect; } - (VAPView *)mp4Effect { if (!_mp4Effect) { _mp4Effect = [[VAPView alloc] init]; _mp4Effect.contentMode = UIViewContentModeScaleAspectFit; } return _mp4Effect; } - (XPRoomGiftAnimationParser *)mp4Parser { if (!_mp4Parser) { _mp4Parser = [[XPRoomGiftAnimationParser alloc] init]; } return _mp4Parser; } - (UIActivityIndicatorView *)loading { if (!_loading) { UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite]; indicator.translatesAutoresizingMaskIntoConstraints = NO; indicator.hidesWhenStopped = YES; _loading = indicator; } return _loading; } - (NetImageView *)avatarHeadViewImageView { if (!_avatarHeadViewImageView) { _avatarHeadViewImageView = [[NetImageView alloc] init]; _avatarHeadViewImageView.contentMode = UIViewContentModeScaleAspectFit; } return _avatarHeadViewImageView; } - (NetImageView *)avatarView { if (!_avatarView) { NetImageConfig * config = [[NetImageConfig alloc]init]; config.imageType = ImageTypeUserIcon; config.placeHolder = [UIImageConstant defaultAvatarPlaceholder]; _avatarView = [[NetImageView alloc] initWithConfig:config]; [_avatarView setCornerRadius:kGetScaleWidth(73)/2 corners:kCALayerMinXMinYCorner | kCALayerMaxXMinYCorner | kCALayerMinXMaxYCorner | kCALayerMaxXMaxYCorner borderWidth:2 borderColor:UIColorFromRGB(0xFBD99A)]; } return _avatarView; } - (SVGAImageView *)avatarHeadWearSVGA { if (!_avatarHeadWearSVGA) { _avatarHeadWearSVGA = [[SVGAImageView alloc] init]; _avatarHeadWearSVGA.contentMode = UIViewContentModeScaleAspectFit; _avatarHeadWearSVGA.autoPlay = YES; _avatarHeadWearSVGA.loops = 0; _avatarHeadWearSVGA.clearsAfterStop = YES; } return _avatarHeadWearSVGA; } @end