Files
peko-ios/YuMi/Modules/YMMine/View/Medals/MedalsViewController.m

1253 lines
44 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.

//
// MedalsViewController.m
// YuMi
//
// Created by P on 2025/6/17.
//
#import "MedalsViewController.h"
#import "MedalsPresenter.h"
#import "UserInfoModel.h"
#import "TYCyclePagerView.h"
#import "MedalsCollectionViewCell.h"
#import "MedalsCyclePagerCell.h"
#import "MedalsDetailView.h"
#import "MedalsWearingViewController.h"
#import "MedalsRankViewController.h"
#import <QGVAPWrapView.h>
#import "XPRoomGiftAnimationParser.h"
typedef enum : NSInteger {
MedalsCenterTab_TaskMedals = 1,
MedalsCenterTab_ActivityMedals = 2,
MedalsCenterTab_GloryMedals = 3,
} MedalsCenterTabType;
typedef enum : NSInteger {
MedalsCenterDisplayType_Mine,
MedalsCenterDisplayType_Other,
MedalsCenterDisplayType_Square
} MedalsCenterDisplayType;
@interface MedalsViewController () <MedalsPresenterProtocol, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, TYCyclePagerViewDataSource, TYCyclePagerViewDelegate, UICollectionViewDelegate>
@property (nonatomic, strong) UserInfoModel *userInfo;
@property (nonatomic, copy) NSArray <UIButton *> *centerTabButtons;
@property (nonatomic, strong) UILabel *medalDescLabel;
@property (nonatomic, strong) UIButton *emptyUserMedalButton;
@property (nonatomic, strong) TYCyclePagerView *medalsCyclePagerView;
@property (nonatomic, strong) UIView *emptyView;
@property (nonatomic, strong) UICollectionView *medalsCollectionView;
@property (nonatomic, strong) UIStackView *centerTabsStackView;
@property (nonatomic, strong) NSMutableArray <MedalSeriesItemVo *>*datasourceTaskMedals;
@property (nonatomic, strong) NSMutableArray <MedalSeriesItemVo *>*datasourceActivityMedals;
@property (nonatomic, strong) NSMutableArray <MedalSeriesItemVo *>*datasourceGloryMedals;
@property (nonatomic, copy) NSArray <MedalVo *> *useMedals;
@property (nonatomic, assign) NSInteger currentPageTaskMedals;
@property (nonatomic, assign) NSInteger currentPageActivityMedals;
@property (nonatomic, assign) NSInteger currentPageGloryMedals;
@property (nonatomic, assign) MedalsCenterTabType currentTabType;
@property (nonatomic, assign) MedalsCenterDisplayType displayType;
@property (nonatomic, strong) UserMedalsModel *userMedalsModel;
@property (nonatomic, strong) NSMutableArray <MedalSeriesVo *>*taskSquareMedalVo;
@property (nonatomic, strong) NSMutableArray <MedalSeriesVo *>*activitySquareMedalVo;
@property (nonatomic, strong) NSMutableArray <MedalSeriesVo *>*glorySquareMedalVo;
@property (nonatomic, strong) UIImageView *otherBG;
@property (nonatomic, strong) NetImageView *otherAvatar;
@property (nonatomic, strong) NetImageView *otherMedal;
@property (nonatomic, strong) VAPView *otherMP4View;
@property (nonatomic, strong) XPRoomGiftAnimationParser *mp4Parser;
@property (nonatomic, strong) UILabel *otherNameLabel;
@property (nonatomic, strong) UILabel *otherCountLabel;
@property (nonatomic, strong) UserMedalsModel *otherMedalsModel;
// 自动轮播相关属性
@property (nonatomic, strong) NSTimer *autoScrollTimer;
@property (nonatomic, assign) NSInteger currentAutoScrollIndex;
@end
@implementation MedalsViewController
- (instancetype)initForMyMedals:(UserInfoModel *)userInfo {
self = [super init];
if (self) {
self.displayType = MedalsCenterDisplayType_Mine;
self.userInfo = userInfo;
}
return self;
}
- (instancetype)initForOtherMedals:(UserInfoModel *)userInfo {
self = [super init];
if (self) {
self.displayType = MedalsCenterDisplayType_Other;
self.userInfo = userInfo;
}
return self;
}
- (instancetype)initForMedalsSquare {
self = [super init];
if (self) {
self.displayType = MedalsCenterDisplayType_Square;
}
return self;
}
- (BOOL)isHiddenNavBar {
return YES;
}
- (MedalsPresenter *)createPresenter {
return [[MedalsPresenter alloc] init];
}
- (void)dealloc {
[self stopAutoScroll];
[self stopOtherMedalMP4Playback];
}
- (void)viewDidLoad {
[super viewDidLoad];
[self setupUI];
[self setupData];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
// 确保可见的 cell 开始播放
[self startVisibleCellsPlayback];
// 如果有佩戴的勋章,再次确保居中显示
if (self.useMedals.count > 0 && !self.medalsCyclePagerView.hidden) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self.medalsCyclePagerView scrollToItemAtIndex:0 animate:NO];
});
}
// 重新启动自动轮播(如果有多个勋章且在广场页面)
if (self.useMedals.count > 1 && !self.medalsCyclePagerView.hidden && self.displayType == MedalsCenterDisplayType_Square) {
[self startAutoScroll:self.currentAutoScrollIndex];
}
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
// 停止所有播放
[self stopAllCellsPlayback];
// 停止自动轮播
[self stopAutoScroll];
// 停止其他用户勋章的MP4播放
[self stopOtherMedalMP4Playback];
}
- (void)stopAllCellsPlayback {
// 停止所有 cell 的播放
NSArray *visibleCells = self.medalsCyclePagerView.collectionView.visibleCells;
for (UICollectionViewCell *cell in visibleCells) {
if ([cell isKindOfClass:[MedalsCyclePagerCell class]]) {
[(MedalsCyclePagerCell *)cell didEndDisplaying];
}
}
}
#pragma mark - 自动轮播方法
/**
* 启动自动轮播
* @param userSelectedIndex 用户选择的起始索引如果无效则默认从0开始
*/
- (void)startAutoScroll:(NSInteger)userSelectedIndex {
[self stopAutoScroll]; // 先停止之前的定时器
// 设置当前索引
if (userSelectedIndex >= 0 && userSelectedIndex < self.useMedals.count) {
self.currentAutoScrollIndex = userSelectedIndex;
} else {
self.currentAutoScrollIndex = 0;
}
NSTimeInterval time = 5;
// 总是创建新的定时器(因为已经在上面停止了旧的)
self.autoScrollTimer = [NSTimer scheduledTimerWithTimeInterval:time
target:self
selector:@selector(autoScrollToNextItem)
userInfo:nil
repeats:YES];
}
- (void)stopAutoScroll {
if (self.autoScrollTimer) {
[self.autoScrollTimer invalidate];
self.autoScrollTimer = nil;
}
}
- (void)autoScrollToNextItem {
if (self.useMedals.count <= 1) {
[self stopAutoScroll];
return;
}
// 计算下一个索引,实现循环滚动
self.currentAutoScrollIndex = (self.currentAutoScrollIndex + 1) % self.useMedals.count;
// 滚动到下一个位置
[self.medalsCyclePagerView scrollToItemAtIndex:self.currentAutoScrollIndex animate:YES];
}
/**
* Tab 切换时重置自动滚动状态
* 停止当前定时器重置索引为0准备从第一个元素重新开始轮播
*/
- (void)resetAutoScrollOnTabChange {
// 停止当前的自动滚动定时器
[self stopAutoScroll];
// 重置滚动索引为 0确保切换 tab 后从第一个元素开始显示
self.currentAutoScrollIndex = 0;
// 注意:新的自动滚动将在数据更新后的 _updateWearingInfo 方法中重新启动
}
#pragma mark - UI
- (void)setupUI {
[self setupBackground];
if (self.displayType != MedalsCenterDisplayType_Other) {
if (self.userInfo.medals.medalCount == 0) {
[self setupEmptyUserMedals];
} else {
[self setupWearingUserMedals];
}
} else {
[self setupOthersMedalInfo];
}
[self setupCenterTabs];
[self setupBottomMedalsList];
[self setupEmptyView];
[self setupNavigationBar];
if (self.displayType == MedalsCenterDisplayType_Mine) {
[self setupWearingButton];
}
}
- (void)setupNavigationBar {
NSString *title = @"";
NSArray *navigationButtons = [NSArray array];
switch (self.displayType) {
case MedalsCenterDisplayType_Mine:
title = YMLocalizedString(@"20.20.61_text_1");
navigationButtons = @[[self medalsRankButton],
[self medalsSquareButton]];
break;
case MedalsCenterDisplayType_Other:
title = [NSString stringWithFormat:YMLocalizedString(@"20.20.61_text_14"),
self.userInfo.nick];
break;
case MedalsCenterDisplayType_Square:
title = YMLocalizedString(@"20.20.61_text_10");
break;
default:
break;
}
[self setupCustomNavigationBar:^{}
title:title
titleColor:[UIColor whiteColor]];
[self setupCustonNavigationRightButtons:navigationButtons
sizes:@[
[NSValue valueWithCGSize:CGSizeMake(22, 22)],
[NSValue valueWithCGSize:CGSizeMake(22, 22)]
]];
}
- (void)setupBackground {
self.view.backgroundColor = UIColorFromRGB(0x1B0043);
UIImageView *bottomBg = [self bottomBG];
[self.view addSubview:bottomBg];
if (self.displayType == MedalsCenterDisplayType_Other) {
[bottomBg mas_makeConstraints:^(MASConstraintMaker *make) {
make.bottom.leading.trailing.mas_equalTo(self.view);
make.top.mas_equalTo(self.view).offset(66 + 98 + 44 + kSafeAreaTopHeight + 20);
}];
} else {
UIImageView *topBg = [self topBG];
[self.view addSubview:topBg];
[topBg mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.leading.trailing.mas_equalTo(self.view);
make.height.mas_equalTo(kGetScaleWidth(314));
}];
[bottomBg mas_makeConstraints:^(MASConstraintMaker *make) {
make.bottom.leading.trailing.mas_equalTo(self.view);
// make.height.mas_equalTo(kGetScaleWidth(445));
make.top.mas_equalTo(topBg.mas_bottom).offset(44);
}];
}
}
- (void)setupOthersMedalInfo {
UIImageView *bg = [[UIImageView alloc] initWithImage:kImage(@"medals_other_bg")];
[self.view addSubview:bg];
[bg mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(80);
make.leading.trailing.mas_equalTo(self.view).inset(12);
make.height.mas_equalTo(kGetScaleWidth(98));
}];
self.otherBG = bg;
[self.view addSubview:self.otherAvatar];
[self.otherAvatar mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.mas_equalTo(bg);
make.leading.mas_equalTo(bg).offset(15);
make.size.mas_equalTo(CGSizeMake(53, 53));
}];
self.otherNameLabel = [UILabel labelInitWithText:@""
font:kFontSemibold(15)
textColor:UIColorFromRGB(0x313131)];
[self.view addSubview:self.otherNameLabel];
[self.otherNameLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.leading.mas_equalTo(self.otherAvatar.mas_trailing).offset(10);
make.top.mas_equalTo(self.otherAvatar);
}];
UIImageView *rankIcon = [[UIImageView alloc] initWithImage:kImage(@"medals_icon_other")];
[self.view addSubview:rankIcon];
[rankIcon mas_makeConstraints:^(MASConstraintMaker *make) {
make.leading.mas_equalTo(self.otherAvatar.mas_trailing).offset(10);
make.bottom.mas_equalTo(self.otherAvatar);
make.size.mas_equalTo(CGSizeMake(22, 22));
}];
self.otherCountLabel = [UILabel labelInitWithText:@""
font:kFontMedium(20)
textColor:UIColorFromRGB(0x313131)];
[self.view addSubview:self.otherCountLabel];
[self.otherCountLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.leading.mas_equalTo(rankIcon.mas_trailing).offset(6);
make.centerY.mas_equalTo(rankIcon);
}];
self.otherMedal = [[NetImageView alloc] initWithImage:kImage(@"medals_empty_other")];
[self.view addSubview:self.otherMedal];
[self.otherMedal mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.mas_equalTo(bg);
make.trailing.mas_equalTo(bg).offset(-15);
make.size.mas_equalTo(CGSizeMake(81, 81));
}];
[self.view addSubview:self.otherMP4View];
[self.otherMP4View mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.mas_equalTo(bg);
make.trailing.mas_equalTo(bg).offset(-15);
make.size.mas_equalTo(CGSizeMake(80, 80));
}];
}
- (void)setupCenterTabs {
self.centerTabsStackView = [self centerTabStack];
[self.view addSubview:self.centerTabsStackView];
[self.centerTabsStackView mas_makeConstraints:^(MASConstraintMaker *make) {
if (self.displayType == MedalsCenterDisplayType_Other) {
make.top.mas_equalTo(self.otherBG.mas_bottom).offset(18);
} else {
make.top.mas_equalTo(kGetScaleWidth(314));
}
make.height.mas_equalTo(44);
make.leading.trailing.mas_equalTo(self.view);
}];
}
- (void)setupWearingButton {
UIView *wearingBg = [[UIView alloc] init];
[wearingBg addGradientBackgroundWithColors:@[
UIColorFromRGB(0xf2e7ff),
UIColorFromRGB(0xb497f6)
] startPoint:CGPointMake(0, 0.5) endPoint:CGPointMake(1, 0.5) cornerRadius:25/2];
[wearingBg setAllCornerRadius:25/2 borderWidth:1 borderColor:[UIColor whiteColor]];
[self.view addSubview:wearingBg];
UIButton *wearingButton = [self wearingButton];
[self.view addSubview:wearingButton];
[wearingButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(90);
make.trailing.mas_equalTo(-12);
make.height.mas_equalTo(25);
}];
[wearingBg mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.mas_equalTo(wearingButton).insets(UIEdgeInsetsMake(0, -25, 0, -25));
}];
}
- (void)setupEmptyUserMedals {
[self.view addSubview:self.medalsCyclePagerView];
[self.view addSubview:self.emptyUserMedalButton];
[self.emptyUserMedalButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.width.height.mas_equalTo(184);
make.centerX.mas_equalTo(self.view);
make.top.mas_equalTo(100);
}];
[self.medalsCyclePagerView mas_makeConstraints:^(MASConstraintMaker *make) {
make.center.mas_equalTo(self.emptyUserMedalButton);
make.width.mas_equalTo([UIScreen mainScreen].bounds.size.width);
// make.width.mas_equalTo(184*3);
make.height.mas_equalTo(self.emptyUserMedalButton);
}];
[self.view addSubview:self.medalDescLabel];
if (self.displayType != MedalsCenterDisplayType_Square) {
self.medalDescLabel.text = YMLocalizedString(@"20.20.61_text_6");
}
[self.medalDescLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(kGetScaleWidth(290));
make.leading.trailing.mas_equalTo(self.view).inset(20);
make.height.mas_equalTo(20);
}];
}
- (void)setupWearingUserMedals {
// // 添加 TYCyclePagerView 用于显示佩戴的勋章
// [self.view addSubview:self.medalsCyclePagerView];
// [self.medalsCyclePagerView mas_makeConstraints:^(MASConstraintMaker *make) {
// make.top.mas_equalTo(100);
// make.centerX.mas_equalTo(self.view);
//// make.width.mas_equalTo([UIScreen mainScreen].bounds.size.width);
// make.width.height.mas_equalTo(184);
// }];
[self.view addSubview:self.medalDescLabel];
self.medalDescLabel.text = @"显示过期时间";//YMLocalizedString(@"20.20.61_text_6");
[self.medalDescLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(kGetScaleWidth(290));
make.leading.trailing.mas_equalTo(self.view).inset(20);
make.height.mas_equalTo(20);
}];
}
- (void)setupScrollMedalsList {
}
- (void)setupBottomMedalsList {
[self.view addSubview:self.medalsCollectionView];
[self.medalsCollectionView mas_makeConstraints:^(MASConstraintMaker *make) {
make.bottom.mas_equalTo(self.view);
make.trailing.leading.mas_equalTo(self.view).inset(26);
make.top.mas_equalTo(self.centerTabsStackView.mas_bottom).offset(68);
}];
// 添加下拉刷新
MJRefreshNormalHeader *header = [MJRefreshNormalHeader headerWithRefreshingTarget:self refreshingAction:@selector(headerRefresh)];
header.lastUpdatedTimeLabel.hidden = YES;
self.medalsCollectionView.mj_header = header;
// 添加上拉加载更多
MJRefreshBackNormalFooter *footer = [MJRefreshBackNormalFooter footerWithRefreshingTarget:self refreshingAction:@selector(footerRefresh)];
self.medalsCollectionView.mj_footer = footer;
}
- (void)setupEmptyView {
self.emptyView.hidden = YES;
[self.view insertSubview:self.emptyView
belowSubview:self.medalsCollectionView];
[self.emptyView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.leading.trailing.mas_equalTo(self.medalsCollectionView);
make.height.mas_equalTo(200);
}];
}
#pragma mark - Refresh Methods
- (void)headerRefresh {
NSInteger page = 1;
switch (self.currentTabType) {
case MedalsCenterTab_TaskMedals:
self.currentPageTaskMedals = 1;
page = self.currentPageTaskMedals;
break;
case MedalsCenterTab_ActivityMedals:
self.currentPageActivityMedals = 1;
page = self.currentPageActivityMedals;
break;
case MedalsCenterTab_GloryMedals:
self.currentPageGloryMedals = 1;
page = self.currentPageGloryMedals;
break;
default:
break;
}
[self loadMedalsList:self.currentTabType page:page];
}
- (void)footerRefresh {
NSInteger page = 1;
switch (self.currentTabType) {
case MedalsCenterTab_TaskMedals:
self.currentPageTaskMedals += 1;
page = self.currentPageTaskMedals;
break;
case MedalsCenterTab_ActivityMedals:
self.currentPageActivityMedals += 1;
page = self.currentPageActivityMedals;
break;
case MedalsCenterTab_GloryMedals:
self.currentPageGloryMedals += 1;
page = self.currentPageGloryMedals;
break;
default:
break;
}
[self loadMedalsList:self.currentTabType page:page];
}
- (void)endReresh {
[self.medalsCollectionView.mj_header endRefreshing];
[self.medalsCollectionView.mj_footer endRefreshing];
}
#pragma mark - Load datas
- (void)setupData {
self.datasourceTaskMedals = @[].mutableCopy;
self.datasourceActivityMedals = @[].mutableCopy;
self.datasourceGloryMedals = @[].mutableCopy;
self.currentPageTaskMedals = 1;
self.currentPageActivityMedals = 1;
self.currentPageGloryMedals = 1;
self.currentTabType = MedalsCenterTab_TaskMedals;
[self loadMedalsList:self.currentTabType page:1];
}
- (void)loadMedalsList:(MedalsCenterTabType)tabType page:(NSInteger)tabPage {
if (self.displayType == MedalsCenterDisplayType_Square) {
[self.presenter squareMedals:tabPage
type:tabType];
} else {
[self.presenter userMedals:self.userInfo.uid
page:tabPage
type:tabType];
}
}
#pragma mark - MedalsPresenterProtocol
- (void)userMedalsSuccess:(UserMedalsModel *)userMedalsModel {
self.userMedalsModel = userMedalsModel;
[self endReresh];
[self _updateDataSource:userMedalsModel.medalSeries];
[self _updateOtherInfo:userMedalsModel];
[self _updateWearingInfo];
}
- (void)userMedalsFailure {
[self endReresh];
// 如果是加载更多失败,页码需要回退
switch (self.currentTabType) {
case MedalsCenterTab_TaskMedals:
if (self.currentPageTaskMedals > 1) {
self.currentPageTaskMedals--;
}
break;
case MedalsCenterTab_ActivityMedals:
if (self.currentPageActivityMedals > 1) {
self.currentPageActivityMedals--;
}
break;
case MedalsCenterTab_GloryMedals:
if (self.currentPageGloryMedals > 1) {
self.currentPageGloryMedals--;
}
break;
default:
break;
}
[self _updateDataSource:@[]];
}
- (void)squareMedalsSuccess:(NSArray <MedalSeriesVo *>*)squareMedalsModel {
switch (self.currentTabType) {
case MedalsCenterTab_TaskMedals:
if (self.currentPageTaskMedals == 1) {
self.taskSquareMedalVo = squareMedalsModel.mutableCopy;
} else {
[self.taskSquareMedalVo addObjectsFromArray:squareMedalsModel];
}
break;
case MedalsCenterTab_ActivityMedals:
if (self.currentPageActivityMedals == 1) {
self.activitySquareMedalVo = squareMedalsModel.mutableCopy;
} else {
[self.activitySquareMedalVo addObjectsFromArray:squareMedalsModel];
}
break;
case MedalsCenterTab_GloryMedals:
if (self.currentPageGloryMedals == 1) {
self.glorySquareMedalVo = squareMedalsModel.mutableCopy;
} else {
[self.glorySquareMedalVo addObjectsFromArray:squareMedalsModel];
}
break;
default:
break;
}
[self endReresh];
[self _updateDataSource:squareMedalsModel];
[self _updateWearingInfo];
}
- (void)squareMedalsFailure {
[self endReresh];
// 如果是加载更多失败,页码需要回退
switch (self.currentTabType) {
case MedalsCenterTab_TaskMedals:
if (self.currentPageTaskMedals > 1) {
self.currentPageTaskMedals--;
}
break;
case MedalsCenterTab_ActivityMedals:
if (self.currentPageActivityMedals > 1) {
self.currentPageActivityMedals--;
}
break;
case MedalsCenterTab_GloryMedals:
if (self.currentPageGloryMedals > 1) {
self.currentPageGloryMedals--;
}
break;
default:
break;
}
}
- (void)_updateWearingInfo {
if (self.displayType == MedalsCenterDisplayType_Mine) {
self.useMedals = self.userMedalsModel.useMedals;
} else if (self.displayType == MedalsCenterDisplayType_Square) {
NSArray *arr = [NSArray array];
NSMutableArray *editArr = [NSMutableArray array];
switch (self.currentTabType) {
case MedalsCenterTab_TaskMedals:
arr = self.taskSquareMedalVo.copy;
break;
case MedalsCenterTab_ActivityMedals:
arr = self.activitySquareMedalVo.copy;
break;
case MedalsCenterTab_GloryMedals:
arr = self.glorySquareMedalVo.copy;
break;
default:
break;
}
for (MedalSeriesVo *seriesVO in arr) {
for (MedalSeriesItemVo *item in seriesVO.medalSeries) {
// 遍历所有medalSeries找到最高级别的
for (MedalVo *medalVo in item.medalVos) {
if (medalVo.level == item.medalLevel) {
[editArr addObject:medalVo];
}
}
}
}
self.useMedals = editArr.copy;
}
if (self.displayType != MedalsCenterDisplayType_Other) {
if (self.useMedals.count > 0 ) {
self.emptyUserMedalButton.hidden = YES;
self.medalsCyclePagerView.hidden = NO;
[self.medalsCyclePagerView reloadData];
if (self.useMedals.count > 1 && self.displayType == MedalsCenterDisplayType_Square) {
// 启动自动轮播,从第一个位置开始
[self startAutoScroll:0];
// 确保滚动到第一个位置
dispatch_async(dispatch_get_main_queue(), ^{
[self.medalsCyclePagerView scrollToItemAtIndex:0 animate:NO];
});
} else {
// 停止自动轮播
[self stopAutoScroll];
}
} else {
self.emptyUserMedalButton.hidden = NO;
self.medalsCyclePagerView.hidden = YES;
}
}
}
- (void)startVisibleCellsPlayback {
// 获取所有可见的 cell 并启动播放
NSArray *visibleCells = self.medalsCyclePagerView.collectionView.visibleCells;
for (UICollectionViewCell *cell in visibleCells) {
if ([cell isKindOfClass:[MedalsCyclePagerCell class]]) {
[(MedalsCyclePagerCell *)cell willDisplay];
}
}
}
- (void)_updateOtherInfo:(UserMedalsModel *)userModel {
_otherMedalsModel = userModel;
if (self.displayType == MedalsCenterDisplayType_Other) {
self.otherAvatar.imageUrl = userModel.avatar;
self.otherNameLabel.text = userModel.nick;
self.otherCountLabel.text = @(userModel.medalNum).stringValue;
MedalVo *useMedal = [[userModel useMedals] xpSafeObjectAtIndex:0];
if (useMedal) {
if ([useMedal.picUrl hasSuffix:@"mp4"]) {
// 显示客态的 MP4 播放
[self displayOtherMedalMp4:useMedal.picUrl];
} else {
// 显示客态的 图片
[self displayOtherMedalImage:useMedal.picUrl];
}
} else {
// 没有勋章时显示默认图片
[self displayOtherMedalImage:nil];
}
}
}
#pragma mark - 其他用户勋章显示方法
/**
* 显示其他用户的勋章图片
* @param imageUrl 图片URL如果为nil则显示默认图片
*/
- (void)displayOtherMedalImage:(NSString *)imageUrl {
// 停止MP4播放
[self stopOtherMedalMP4Playback];
// 显示图片隐藏MP4视图
self.otherMP4View.hidden = YES;
self.otherMedal.hidden = NO;
if (imageUrl && imageUrl.length > 0) {
self.otherMedal.imageUrl = imageUrl;
} else {
// 显示默认空勋章图片
self.otherMedal.image = kImage(@"medals_empty_other");
}
}
/**
* 显示其他用户的勋章MP4动画
* @param mp4Url MP4文件URL
*/
- (void)displayOtherMedalMp4:(NSString *)mp4Url {
if (!mp4Url || mp4Url.length == 0) {
[self displayOtherMedalImage:nil];
return;
}
// 停止之前的MP4播放
[self stopOtherMedalMP4Playback];
// 显示MP4视图隐藏图片
self.otherMP4View.hidden = NO;
self.otherMedal.hidden = YES;
// 初始化MP4解析器
if (!self.mp4Parser) {
self.mp4Parser = [[XPRoomGiftAnimationParser alloc] init];
}
@kWeakify(self);
[self.mp4Parser parseWithURL:mp4Url
completionBlock:^(NSString * _Nullable videoUrl) {
@kStrongify(self);
if (![NSString isEmpty:videoUrl] && !self.otherMP4View.hidden) {
// 静音播放,因为是展示其他用户的勋章
[self.otherMP4View setMute:YES];
[self.otherMP4View playHWDMP4:videoUrl repeatCount:-1 delegate:nil];
}
} failureBlock:^(NSError * _Nullable error) {
@kStrongify(self);
NSLog(@"Failed to parse other user medal mp4: %@", error);
// 播放失败时显示图片
[self displayOtherMedalImage:nil];
}];
}
/**
* 停止其他用户勋章的MP4播放
*/
- (void)stopOtherMedalMP4Playback {
if (self.otherMP4View) {
[self.otherMP4View stopHWDMP4];
}
}
- (void)_updateDataSource:(NSArray <MedalSeriesVo *>*)models {
NSArray *targetArr = models;
NSMutableArray *itemDataSources = [NSMutableArray array];
MedalSeriesVo *series = [models xpSafeObjectAtIndex:0];
if (series) {
targetArr = series.medalSeries;
}
itemDataSources = targetArr.mutableCopy;
if (targetArr.count < [self.presenter pageSize]) {
[self.medalsCollectionView.mj_footer endRefreshingWithNoMoreData];
} else {
[self.medalsCollectionView.mj_footer resetNoMoreData];
}
switch (self.currentTabType) {
case MedalsCenterTab_TaskMedals:
if (self.currentPageTaskMedals == 1) {
self.emptyView.hidden = (targetArr.count != 0);
self.datasourceTaskMedals = itemDataSources;
} else {
[self.datasourceTaskMedals addObjectsFromArray:itemDataSources];
}
break;
case MedalsCenterTab_ActivityMedals:
if (self.currentPageActivityMedals == 1) {
self.emptyView.hidden = (targetArr.count != 0);
self.datasourceActivityMedals = itemDataSources;
} else {
[self.datasourceActivityMedals addObjectsFromArray:itemDataSources];
}
break;
case MedalsCenterTab_GloryMedals:
if (self.currentPageGloryMedals == 1) {
self.emptyView.hidden = (targetArr.count != 0);
self.datasourceGloryMedals = itemDataSources;
} else {
[self.datasourceGloryMedals addObjectsFromArray:itemDataSources];
}
break;
default:
break;
}
[self.medalsCollectionView reloadData];
}
#pragma mark - 数据刷新
- (void)refreshDataAfterWearingChange {
// 只有在 Mine 模式下才需要刷新(因为只有自己的勋章页面会受到佩戴变化影响)
if (self.displayType == MedalsCenterDisplayType_Mine) {
// 重新加载当前 tab 的数据
[self loadMedalsList:self.currentTabType page:1];
}
}
#pragma mark - Button actions
- (void)didTapSquareButton:(UIButton *)sender {
MedalsViewController *vc = [[MedalsViewController alloc] initForMedalsSquare];
[self.navigationController pushViewController:vc animated:YES];
}
- (void)didTapRankButton:(UIButton *)sender {
MedalsRankViewController *vc = [[MedalsRankViewController alloc] init];
[self.navigationController pushViewController:vc animated:YES];
}
- (void)didTapWearingButton:(UIButton *)sender {
MedalsWearingViewController *vc = [[MedalsWearingViewController alloc] init];
vc.userInfo = self.userInfo;
// 设置数据变化回调
@kWeakify(self);
vc.dataChangedCallback = ^{
@kStrongify(self);
// 刷新数据
[self refreshDataAfterWearingChange];
};
[self addChildViewController:vc];
[self.view addSubview:vc.view];
}
- (void)didTapEmptyMedalButton:(UIButton *)sender {
MedalsWearingViewController *vc = [[MedalsWearingViewController alloc] init];
vc.userInfo = self.userInfo;
// 设置数据变化回调
@kWeakify(self);
vc.dataChangedCallback = ^{
@kStrongify(self);
// 刷新数据
[self refreshDataAfterWearingChange];
};
[self addChildViewController:vc];
[self.view addSubview:vc.view];
}
- (void)didTapCenterTab:(UIButton *)sender {
if (sender.isSelected == YES) {
return;
}
for (UIButton *b in self.centerTabButtons) {
b.selected = NO;
}
sender.selected = YES;
self.currentTabType = sender.tag;
// 切换 tab 时重置自动滚动
[self resetAutoScrollOnTabChange];
[self loadMedalsList:self.currentTabType page:1];
}
#pragma mark - UICollectionView DataSource & Delegate
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
switch (self.currentTabType) {
case MedalsCenterTab_TaskMedals:
return self.datasourceTaskMedals.count;
break;
case MedalsCenterTab_ActivityMedals:
return self.datasourceActivityMedals.count;
break;
case MedalsCenterTab_GloryMedals:
return self.datasourceGloryMedals.count;
break;
default:
break;
}
}
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
MedalsCollectionViewCell *cell = [MedalsCollectionViewCell cellFor:collectionView atIndexPath:indexPath];
[cell updateCell:[self loadModel:indexPath.item]
isForSquare:self.displayType == MedalsCenterDisplayType_Square
isForMine:self.displayType == MedalsCenterDisplayType_Mine];
return cell;
}
// 处理 cell 的可见性
- (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath {
if (collectionView == self.medalsCollectionView) {
if ([cell isKindOfClass:[MedalsCollectionViewCell class]]) {
[(MedalsCollectionViewCell *)cell willDisplay];
}
}
}
- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath {
if (collectionView == self.medalsCollectionView) {
if ([cell isKindOfClass:[MedalsCollectionViewCell class]]) {
[(MedalsCollectionViewCell *)cell didEndDisplaying];
}
}
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
if (collectionView == self.medalsCyclePagerView.collectionView) {
return;
}
MedalsDetailView *view = [[MedalsDetailView alloc] initWithFrame:self.view.bounds];
[view updateSeriesItem:[self loadModel:indexPath.item]
isMine:self.displayType == MedalsCenterDisplayType_Mine || self.displayType == MedalsCenterDisplayType_Other];
[self.view addSubview:view];
}
- (MedalSeriesItemVo *)loadModel:(NSInteger)row {
MedalSeriesItemVo *model = nil;
switch (self.currentTabType) {
case MedalsCenterTab_TaskMedals:
model = [self.datasourceTaskMedals xpSafeObjectAtIndex:row];
break;
case MedalsCenterTab_ActivityMedals:
model = [self.datasourceActivityMedals xpSafeObjectAtIndex:row];
break;
case MedalsCenterTab_GloryMedals:
model = [self.datasourceGloryMedals xpSafeObjectAtIndex:row];
break;
default:
break;
}
return model;
}
- (MedalSeriesVo *)loadDetailModel:(NSInteger)row {
MedalSeriesVo *model = nil;
switch (self.currentTabType) {
case MedalsCenterTab_TaskMedals:
model = [self.taskSquareMedalVo xpSafeObjectAtIndex:row];
break;
case MedalsCenterTab_ActivityMedals:
model = [self.activitySquareMedalVo xpSafeObjectAtIndex:row];
break;
case MedalsCenterTab_GloryMedals:
model = [self.glorySquareMedalVo xpSafeObjectAtIndex:row];
break;
default:
break;
}
return model;
}
#pragma mark - TYCyclePagerView DataSource & Delegate
- (NSInteger)numberOfItemsInPagerView:(TYCyclePagerView *)pageView {
return self.useMedals.count;
}
- (__kindof UICollectionViewCell *)pagerView:(TYCyclePagerView *)pagerView cellForItemAtIndex:(NSInteger)index {
MedalsCyclePagerCell *cell = [pagerView dequeueReusableCellWithReuseIdentifier:@"MedalsCyclePagerCell" forIndex:index];
MedalVo *vo = [self.useMedals xpSafeObjectAtIndex:index];
[cell updateCell:vo];
return cell;
}
- (TYCyclePagerViewLayout *)layoutForPagerView:(TYCyclePagerView *)pageView {
TYCyclePagerViewLayout *layout = [[TYCyclePagerViewLayout alloc] init];
layout.itemSize = CGSizeMake(184, 184);
layout.itemSpacing = 10;
layout.layoutType = TYCyclePagerTransformLayoutLinear;
layout.itemHorizontalCenter = YES;
return layout;
}
- (void)pagerView:(TYCyclePagerView *)pageView didScrollFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex {
// 用户手动滚动时,更新当前索引,重新开始自动轮播计时
self.currentAutoScrollIndex = toIndex;
// 如果有多个勋章且在广场页面,重新启动自动轮播定时器
if (self.useMedals.count > 1 && self.displayType == MedalsCenterDisplayType_Square) {
[self startAutoScroll:toIndex];
}
if (self.displayType == MedalsCenterDisplayType_Mine) {
MedalVo *vo = [self.useMedals xpSafeObjectAtIndex:toIndex];
self.medalDescLabel.text = [vo expireDateString];
} else {
self.medalDescLabel.text = @"";
}
}
#pragma mark - Lazy load
- (UIButton *)medalsSquareButton {
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button addTarget:self action:@selector(didTapSquareButton:) forControlEvents:UIControlEventTouchUpInside];
[button setBackgroundImage:kImage(@"medals_square") forState:UIControlStateNormal];
return button;
}
- (UIButton *)medalsRankButton {
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button addTarget:self action:@selector(didTapRankButton:) forControlEvents:UIControlEventTouchUpInside];
[button setBackgroundImage:kImage(@"medals_rank") forState:UIControlStateNormal];
return button;
}
- (UIButton *)wearingButton {
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button addTarget:self action:@selector(didTapWearingButton:) forControlEvents:UIControlEventTouchUpInside];
[button setTitle:YMLocalizedString(@"20.20.61_text_2") forState:UIControlStateNormal];
[button setTitleColor:UIColorFromRGB(0x201440) forState:UIControlStateNormal];
button.titleLabel.font = kFontMedium(12);
return button;
}
- (UIImageView *)topBG {
UIImageView *iv = [[UIImageView alloc] initWithImage:kImage(@"medals_top_bg")];
iv.contentMode = UIViewContentModeScaleAspectFit;
return iv;
}
- (UIImageView *)bottomBG {
UIImage *originalImage = kImage(@"medals_bottom_bg");
// 创建可拉伸的图片,让下半部分可以拉伸
// 假设图片高度的上半部分不拉伸,下半部分可拉伸
CGFloat imageHeight = originalImage.size.height;
CGFloat stretchableTopInset = imageHeight * 0.5; // 上半部分不拉伸
CGFloat stretchableBottomInset = 1; // 下半部分保留1像素不拉伸
UIImage *stretchableImage = [originalImage resizableImageWithCapInsets:UIEdgeInsetsMake(stretchableTopInset, 0, stretchableBottomInset, 0)
resizingMode:UIImageResizingModeStretch];
UIImageView *iv = [[UIImageView alloc] initWithImage:stretchableImage];
iv.contentMode = UIViewContentModeScaleToFill; // 使用ScaleToFill来应用拉伸效果
return iv;
}
- (UIButton *)taskMedalsButton:(MedalsCenterTabType)tabType {
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.tag = tabType;
switch (tabType) {
case MedalsCenterTab_TaskMedals:
[button setTitle:YMLocalizedString(@"20.20.61_text_3") forState:UIControlStateNormal];
break;
case MedalsCenterTab_ActivityMedals:
[button setTitle:YMLocalizedString(@"20.20.61_text_4") forState:UIControlStateNormal];
break;
case MedalsCenterTab_GloryMedals:
[button setTitle:YMLocalizedString(@"20.20.61_text_5") forState:UIControlStateNormal];
break;
default:
break;
}
[button addTarget:self action:@selector(didTapCenterTab:) forControlEvents:UIControlEventTouchUpInside];
[button setBackgroundImage:kImage(@"medals_tab_normal") forState:UIControlStateNormal];
[button setBackgroundImage:kImage(@"medals_tab_selected") forState:UIControlStateSelected];
[button setTitleColor:UIColorFromRGB(0xd8a2ff) forState:UIControlStateNormal];
[button setTitleColor:UIColorFromRGB(0xFFFFFF) forState:UIControlStateSelected];
[button.titleLabel setFont:kFontMedium(13)];
[button setAdjustsImageWhenDisabled:NO];
return button;
}
- (UIStackView *)centerTabStack {
UIButton *taskMedalsButton = [self taskMedalsButton:MedalsCenterTab_TaskMedals];
taskMedalsButton.selected = YES;
UIButton *activityMedalsButton = [self taskMedalsButton:MedalsCenterTab_ActivityMedals];
UIButton *gloryMedalsButton = [self taskMedalsButton:MedalsCenterTab_GloryMedals];
self.centerTabButtons = @[
taskMedalsButton,
activityMedalsButton,
gloryMedalsButton
];
UIStackView *stack = [[UIStackView alloc] initWithArrangedSubviews:self.centerTabButtons];
stack.distribution = UIStackViewDistributionFillEqually;
return stack;
}
- (UILabel *)medalDescLabel {
if (!_medalDescLabel) {
_medalDescLabel = [UILabel labelInitWithText:@""
font:kFontRegular(12)
textColor:[UIColor whiteColor]];
_medalDescLabel.textAlignment = NSTextAlignmentCenter;
}
return _medalDescLabel;
}
- (UIButton *)emptyUserMedalButton {
if (!_emptyUserMedalButton) {
_emptyUserMedalButton = [UIButton buttonWithType:UIButtonTypeCustom];
[_emptyUserMedalButton setImage:kImage(@"medals_empty")
forState:UIControlStateNormal];
[_emptyUserMedalButton addTarget:self
action:@selector(didTapEmptyMedalButton:)
forControlEvents:UIControlEventTouchUpInside];
}
return _emptyUserMedalButton;
}
- (UICollectionView *)medalsCollectionView {
if (!_medalsCollectionView) {
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
layout.itemSize = CGSizeMake(kGetScaleWidth(156), kGetScaleWidth(218));
layout.minimumInteritemSpacing = 6;
layout.minimumLineSpacing = 6;
_medalsCollectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
_medalsCollectionView.backgroundColor = [UIColor clearColor];
_medalsCollectionView.delegate = self;
_medalsCollectionView.dataSource = self;
[MedalsCollectionViewCell registerTo:_medalsCollectionView];
}
return _medalsCollectionView;
}
- (UIView *)emptyView {
if (!_emptyView) {
_emptyView = [[UIView alloc] init];
_emptyView.backgroundColor = [UIColor clearColor];
NSString *content = YMLocalizedString(@"20.20.61_text_7.1");
if (self.displayType == MedalsCenterDisplayType_Mine) {
content = YMLocalizedString(@"20.20.61_text_7.2");
}
UILabel *titleLabel = [UILabel labelInitWithText:content
font:kFontRegular(14)
textColor:UIColorFromRGB(0xafb1b3)];
titleLabel.numberOfLines = 2;
titleLabel.textAlignment = NSTextAlignmentCenter;
UIImageView *ufoImageView = [[UIImageView alloc] initWithImage:kImage(@"common_empty_UFO")];
[_emptyView addSubview:ufoImageView];
[_emptyView addSubview:titleLabel];
[ufoImageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.mas_equalTo(_emptyView);
make.top.mas_equalTo(20);
make.size.mas_equalTo(CGSizeMake(110, 110));
}];
[titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.mas_equalTo(_emptyView);
make.top.mas_equalTo(ufoImageView.mas_bottom).offset(10);
make.leading.trailing.mas_equalTo(_emptyView).inset(20);
}];
}
return _emptyView;
}
- (NetImageView *)otherAvatar {
if (!_otherAvatar) {
NetImageConfig *config = [[NetImageConfig alloc] init];
config.placeHolder = [UIImageConstant defaultAvatarPlaceholder];
_otherAvatar = [[NetImageView alloc] initWithConfig:config];
[_otherAvatar setAllCornerRadius:53/2 borderWidth:1 borderColor:[UIColor whiteColor]];
}
return _otherAvatar;
}
- (TYCyclePagerView *)medalsCyclePagerView {
if (!_medalsCyclePagerView) {
_medalsCyclePagerView = [[TYCyclePagerView alloc] init];
_medalsCyclePagerView.dataSource = self;
_medalsCyclePagerView.delegate = self;
_medalsCyclePagerView.backgroundColor = [UIColor clearColor];
_medalsCyclePagerView.isInfiniteLoop = NO;
_medalsCyclePagerView.clipsToBounds = NO;
// _medalsCyclePagerView.autoScrollInterval = 0; // 禁用自动滚动
[_medalsCyclePagerView registerClass:[MedalsCyclePagerCell class]
forCellWithReuseIdentifier:@"MedalsCyclePagerCell"];
// 设置内部 collectionView 的代理,用于处理 cell 的显示和隐藏
// _medalsCyclePagerView.collectionView.delegate = self;
}
return _medalsCyclePagerView;
}
- (VAPView *)otherMP4View {
if (!_otherMP4View) {
_otherMP4View = [[VAPView alloc] init];
_otherMP4View.contentMode = UIViewContentModeScaleAspectFit;
}
return _otherMP4View;
}
@end