// // ShoppingMallViewController.m // YuMi // // Created by P on 2024/11/13. // #import "ShoppingMallViewController.h" #import #import #import "XPRoomGiftAnimationParser.h" #import "MyDressingViewController.h" #import "XPDressSearchViewController.h" #import "ShoppingMallItemPreview.h" #import "ShoppingMallDataPresent.h" #import "ShoppingMallCategoryListView.h" static NSArray *> *DressUpOptions(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 ShoppingMallViewController () @property(nonatomic, strong) ShoppingMallCategoryListView *listView; @property (nonatomic, strong) UIView *playEffectMask; @property (nonatomic, strong) VAPView *mp4Effect; @property(nonatomic, strong) XPRoomGiftAnimationParser *mp4Parser; @property (nonatomic, strong) SVGAImageView *svgaEffect; @property(nonatomic, strong) UIView *bottomControlArea; @property(nonatomic, strong) UILabel *bottomControlPriceLabel; @property(nonatomic, strong) UIButton *bottomControlBuyButton; @property(nonatomic, strong) UIButton *bottomControlGiveButton; @property(nonatomic, strong) DressUpShopModel *selectedModel; @property(nonatomic, strong) UIActivityIndicatorView *loading; @end @implementation ShoppingMallViewController - (ShoppingMallDataPresent *)createPresenter { return [[ShoppingMallDataPresent alloc] init]; } - (BOOL)isHiddenNavBar { return YES; } - (void)viewDidLoad { [super viewDidLoad]; [self setupUI]; } - (void)setupUI { [self setupBackground]; [self setupNavigationBar]; [self setupBottomControlBar]; [self setupContentList]; // [self hideBottomControlArea]; } - (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]; UIButton *myDressButton = [self myDressButton]; [self.view addSubview:titleLabel]; [self.view addSubview:backButton]; [self.view addSubview:myDressButton]; [titleLabel mas_makeConstraints:^(MASConstraintMaker *make) { make.centerX.mas_equalTo(self.view); make.top.mas_equalTo(self.view).offset(kStatusBarHeight); 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)); }]; [myDressButton mas_makeConstraints:^(MASConstraintMaker *make) { make.trailing.mas_equalTo(self.view).offset(-16); make.centerY.mas_equalTo(titleLabel); make.height.mas_equalTo(22); make.width.mas_greaterThanOrEqualTo(84); }]; } - (void)setupBottomControlBar { [self.view addSubview:self.bottomControlArea]; [self.bottomControlArea mas_makeConstraints:^(MASConstraintMaker *make) { make.bottom.mas_equalTo(-200); make.leading.trailing.mas_equalTo(self.view); make.height.mas_equalTo(80); }]; } - (void)setupContentList { NSInteger top = kNavigationHeight; NSInteger bottom = 80 + kSafeAreaBottomHeight; ShoppingMallCategoryListView *listView = [[ShoppingMallCategoryListView alloc] initWithFrame:CGRectMake(0, top, KScreenWidth, KScreenHeight - top)]; listView.bottomSpace = bottom; [self.view insertSubview:listView belowSubview:self.bottomControlArea]; self.listView = listView; @kWeakify(self); listView.fetchDataForPage = ^(NSInteger pageIndex, FetchDataCompletion completion) { @kStrongify(self); [self fetchDataForPage:pageIndex 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.returnSelectedModel = ^(DressUpShopModel * _Nonnull model) { @kStrongify(self); self.selectedModel = model; [self updateBottomControlArea]; }; listView.items = DressUpOptions(); } #pragma mark - - (void)fetchDataForPage:(NSInteger)pageIndex completion:(FetchDataCompletion)completion { dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.25 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [self.presenter loadCategoryItems:pageIndex success:^(NSArray * array) { if (completion) { completion(array); } } failure:^(NSError * _Nonnull error) {}]; }); } - (void)updateBottomControlArea { if (self.selectedModel) { if (self.selectedModel.obtainWay > 1) { self.bottomControlPriceLabel.text = @""; } else { self.bottomControlPriceLabel.attributedText = [self.selectedModel mallItemPricePerDay:NO isFullDisplay:YES]; } } else { self.bottomControlPriceLabel.text = @""; } if ([NSString isEmpty:self.bottomControlPriceLabel.text]) { [self hideBottomControlArea]; } else { [self showBottomControlArea]; } } - (void)showBottomControlArea { if (self.bottomControlArea.hidden) { self.bottomControlArea.hidden = NO; } [UIView animateWithDuration:0.25 animations:^{ [self.bottomControlArea mas_updateConstraints:^(MASConstraintMaker *make) { make.bottom.mas_equalTo(0); }]; [self.bottomControlArea layoutIfNeeded]; } completion:^(BOOL finished) { }]; } - (void)hideBottomControlArea { [self.bottomControlArea mas_updateConstraints:^(MASConstraintMaker *make) { make.bottom.mas_equalTo(80 + kSafeAreaBottomHeight); }]; [self.bottomControlArea layoutIfNeeded]; } - (void)didTapBuy:(id)sender { if (!self.selectedModel) { return; } ShoppingMallItemPreview *preview = [[ShoppingMallItemPreview alloc] initWith:self.selectedModel isForGive:NO]; preview.frame = CGRectMake(0, 0, 284, 353); [TTPopup popupView:preview style:TTPopupStyleAlert]; @kWeakify(self); [preview setBuyWith:^(DressUpShopModel * _Nonnull model) { @kStrongify(self); @kWeakify(self); [self.presenter buyItem:model.dressUpId success:^(id _Nonnull obj) { @kStrongify(self); [TTPopup dismiss]; [self showSuccessToast:YMLocalizedString(@"XPDressUpShopListViewController0")]; } failure:^(NSError * _Nonnull error) { // @kStrongify(self); // [self showErrorToast:error.localizedDescription]; }]; }]; } - (void)didTapGive:(id)sender { if (!self.selectedModel) { return; } XPDressSearchViewController *vc = [[XPDressSearchViewController alloc] init]; vc.selectedModel = self.selectedModel; [self.navigationController pushViewController:vc animated:YES]; } - (void)didTapBack { [self.navigationController popViewControllerAnimated:YES]; } - (void)didTapMyDress { MyDressingViewController *myDressVC = [[MyDressingViewController alloc] init]; [self.navigationController pushViewController:myDressVC animated: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.loading startAnimating]; self.playEffectMask.hidden = NO; 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 - - (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; } - (UIView *)bottomControlArea { if (!_bottomControlArea) { _bottomControlArea = [[UIView alloc] init]; _bottomControlArea.hidden = YES; [_bottomControlArea addGradientBackgroundWithColors:@[UIColorFromRGB(0x012E4D), UIColorFromRGB(0x0F1435)] startPoint:CGPointMake(0.5, 0) endPoint:CGPointMake(0.5, 1) cornerRadius:0]; [_bottomControlArea addSubview:self.bottomControlGiveButton]; [self.bottomControlGiveButton mas_makeConstraints:^(MASConstraintMaker *make) { make.top.mas_equalTo(14); make.trailing.mas_equalTo(-16); make.size.mas_equalTo(CGSizeMake(74, 32)); }]; [_bottomControlArea addSubview:self.bottomControlBuyButton]; [self.bottomControlBuyButton mas_makeConstraints:^(MASConstraintMaker *make) { make.top.mas_equalTo(14); make.trailing.mas_equalTo(self.bottomControlGiveButton.mas_leading).offset(-8); make.size.mas_equalTo(CGSizeMake(74, 32)); }]; [_bottomControlArea addSubview:self.bottomControlPriceLabel]; [self.bottomControlPriceLabel mas_makeConstraints:^(MASConstraintMaker *make) { make.centerY.mas_equalTo(self.bottomControlGiveButton); make.leading.top.mas_equalTo(16); }]; } return _bottomControlArea; } - (UILabel *)bottomControlPriceLabel { if (!_bottomControlPriceLabel) { _bottomControlPriceLabel = [[UILabel alloc] init]; } return _bottomControlPriceLabel; } - (UIButton *)bottomControlBuyButton { if (!_bottomControlBuyButton) { _bottomControlBuyButton = [UIButton buttonWithType:UIButtonTypeCustom]; _bottomControlBuyButton.titleLabel.font = kFontMedium(14); [_bottomControlBuyButton setTitle:YMLocalizedString(@"1.0.30_text_5") forState:UIControlStateNormal]; [_bottomControlBuyButton setTitleColor:UIColorFromRGB(0x51281B) forState:UIControlStateNormal]; [_bottomControlBuyButton addGradientBackgroundWithColors:@[UIColorFromRGB(0xFFE3B2), UIColorFromRGB(0xE9A71D)] startPoint:CGPointMake(0.0, 0.5) endPoint:CGPointMake(1.0, 0.5) cornerRadius:16]; [_bottomControlBuyButton addTarget:self action:@selector(didTapBuy:) forControlEvents:UIControlEventTouchUpInside]; } return _bottomControlBuyButton; } - (UIButton *)bottomControlGiveButton { if (!_bottomControlGiveButton) { _bottomControlGiveButton = [UIButton buttonWithType:UIButtonTypeCustom]; _bottomControlGiveButton.titleLabel.font = kFontMedium(14); [_bottomControlGiveButton setTitle:YMLocalizedString(@"1.0.30_text_6") forState:UIControlStateNormal]; [_bottomControlGiveButton setTitleColor:UIColorFromRGB(0x172055) forState:UIControlStateNormal]; [_bottomControlGiveButton addGradientBackgroundWithColors:@[UIColorFromRGB(0xB2FCFF), UIColorFromRGB(0x4DA2EA)] startPoint:CGPointMake(0.0, 0.5) endPoint:CGPointMake(1.0, 0.5) cornerRadius:16]; [_bottomControlGiveButton addTarget:self action:@selector(didTapGive:) forControlEvents:UIControlEventTouchUpInside]; } return _bottomControlGiveButton; } - (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(@"XPDressUpShopViewController1"); label.textColor = UIColorFromRGB(0xD9E7F7); return label; } - (UIButton *)myDressButton { UIButton *b = [UIButton buttonWithType:UIButtonTypeCustom]; [b addGradientBackgroundWithColors:@[UIColorFromRGB(0x004A4F), UIColorFromRGB(0x11215B)] startPoint:CGPointMake(0.5, 0.0) endPoint:CGPointMake(0.5, 1.0) cornerRadius:11]; [b setCornerRadius:11 corners:kCALayerMaxXMaxYCorner | kCALayerMaxXMinYCorner | kCALayerMinXMaxYCorner | kCALayerMinXMinYCorner borderWidth:1 borderColor:UIColorFromRGB(0x75B4DF)]; NSTextAttachment *iconAttachment = [[NSTextAttachment alloc] init]; iconAttachment.image = kImage(@"mall_my_icon"); iconAttachment.bounds = CGRectMake(8, -2, 14, 14); NSAttributedString *iconString = [NSAttributedString attributedStringWithAttachment:iconAttachment]; NSMutableAttributedString *title = [[NSMutableAttributedString alloc] initWithAttributedString:iconString]; [title insertAttributedString:[[NSAttributedString alloc] initWithString:YMLocalizedString(@"1.0.30_text_8") attributes:@{NSFontAttributeName: kFontMedium(12), NSForegroundColorAttributeName: UIColorFromRGB(0xd9e7f7)}] atIndex:0]; [b setAttributedTitle:title forState:UIControlStateNormal]; CGFloat spacing = 8.0; b.contentEdgeInsets = UIEdgeInsetsMake(0, spacing, 4, spacing); [b addTarget:self action:@selector(didTapMyDress) forControlEvents:UIControlEventTouchUpInside]; return b; } - (UIActivityIndicatorView *)loading { if (!_loading) { UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite]; indicator.translatesAutoresizingMaskIntoConstraints = NO; indicator.hidesWhenStopped = YES; _loading = indicator; } return _loading; } @end