新增 next-chat.mdc 文件以定义对话上下文的规则;在 Assets.xcassets 中添加多个图像资源及其对应的 Contents.json 文件;更新 AttachmentModel.h 中的枚举值以修正飘屏消息类型;在 SessionViewController.h 和 SessionViewController.m 中添加 userInfo 属性并调整相关逻辑;在 SessionListViewController.h 和 SessionListViewController.m 中优化会话列表的展示逻辑;在多个模型和视图文件中进行小幅调整以提升代码可读性和一致性。
This commit is contained in:
7
.cursor/rules/next-chat.mdc
Normal file
7
.cursor/rules/next-chat.mdc
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
description:
|
||||
globs:
|
||||
alwaysApply: false
|
||||
---
|
||||
本次对话的上下文已经太长了,我打算关掉并重新开一个新的会话。
|
||||
你有什么想对你的继任者说的,以便它能更好的理解你当前的工作并顺利继续?
|
21
YuMi/Assets.xcassets/20.20.61/brown_arrow.imageset/Contents.json
vendored
Normal file
21
YuMi/Assets.xcassets/20.20.61/brown_arrow.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "切图 31@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
YuMi/Assets.xcassets/20.20.61/brown_arrow.imageset/切图 31@3x.png
vendored
Normal file
BIN
YuMi/Assets.xcassets/20.20.61/brown_arrow.imageset/切图 31@3x.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 404 B |
21
YuMi/Assets.xcassets/20.20.61/medals_empty_other.imageset/Contents.json
vendored
Normal file
21
YuMi/Assets.xcassets/20.20.61/medals_empty_other.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "切图 70@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
YuMi/Assets.xcassets/20.20.61/medals_empty_other.imageset/切图 70@3x.png
vendored
Normal file
BIN
YuMi/Assets.xcassets/20.20.61/medals_empty_other.imageset/切图 70@3x.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
21
YuMi/Assets.xcassets/20.20.61/medals_icon_other.imageset/Contents.json
vendored
Normal file
21
YuMi/Assets.xcassets/20.20.61/medals_icon_other.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "容器 8456@3x (1).png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
YuMi/Assets.xcassets/20.20.61/medals_icon_other.imageset/容器 8456@3x (1).png
vendored
Normal file
BIN
YuMi/Assets.xcassets/20.20.61/medals_icon_other.imageset/容器 8456@3x (1).png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.3 KiB |
21
YuMi/Assets.xcassets/20.20.61/medals_icon_rank.imageset/Contents.json
vendored
Normal file
21
YuMi/Assets.xcassets/20.20.61/medals_icon_rank.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "容器 8456@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
YuMi/Assets.xcassets/20.20.61/medals_icon_rank.imageset/容器 8456@3x.png
vendored
Normal file
BIN
YuMi/Assets.xcassets/20.20.61/medals_icon_rank.imageset/容器 8456@3x.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
@@ -723,7 +723,7 @@ typedef NS_ENUM(NSUInteger, CustomMessageTypeSuperGift) {
|
||||
Custom_Message_Sub_Super_Gift_Banner = 1066, // 飘屏
|
||||
};
|
||||
///通用飘屏
|
||||
//CustomMessageType_General_Floating_Screen = 105,
|
||||
//CustomMessageType_General_Floating_Screen = 107,
|
||||
typedef NS_ENUM(NSUInteger, CustomMessageTypeGeneralFloatingScreen) {
|
||||
///所有房间
|
||||
Custom_Message_Sub_General_Floating_Screen_One_Room = 1071,//单房间
|
||||
|
@@ -8,7 +8,7 @@
|
||||
#import "MvpViewController.h"
|
||||
#import "SessionListViewController.h"
|
||||
#import <NIMSDK/NIMSDK.h>
|
||||
|
||||
@class UserInfoModel;
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface SessionViewController : MvpViewController
|
||||
@@ -23,6 +23,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
///置顶回话
|
||||
@property (nonatomic,strong) NSMutableDictionary<NIMSession *, NIMStickTopSessionInfo *> *stickTopMessages;
|
||||
|
||||
@property (nonatomic, strong) UserInfoModel *userInfo;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
@@ -104,7 +104,7 @@
|
||||
///导航栏
|
||||
@property (nonatomic,strong) SessionNavView *sessionNavView;
|
||||
@property (nonatomic, strong) UITableView * sessionTableView;
|
||||
@property (nonatomic, strong) UserInfoModel *userInfo;
|
||||
|
||||
@property (nonatomic, strong) UserInfoModel *detailUserInfo;
|
||||
///最后的一条消息
|
||||
@property (nonatomic,strong) NIMMessage *lastMessage;
|
||||
@@ -159,7 +159,9 @@
|
||||
[super viewWillAppear:animated];
|
||||
if (![[[ClientConfig shareConfig].configInfo officialAccountUids] containsObject:self.session.sessionId]) {
|
||||
[self.presenter getFansLike:self.session.sessionId];
|
||||
[self.presenter getUserInfoWithUid:self.session.sessionId];
|
||||
if (!self.userInfo) {
|
||||
[self.presenter getUserInfoWithUid:self.session.sessionId];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -258,7 +260,6 @@
|
||||
default:
|
||||
model = [[MessageUnSupportModel alloc] initWithMessage:message];
|
||||
break;
|
||||
|
||||
}
|
||||
return model;
|
||||
}
|
||||
@@ -595,8 +596,8 @@
|
||||
[XPSkillCardPlayerManager shareInstance].userInfoModel = userInfo;
|
||||
} else {
|
||||
self.userInfo = userInfo;
|
||||
[self.sessionTableView reloadData];
|
||||
}
|
||||
[self.sessionTableView reloadData];
|
||||
}
|
||||
|
||||
#pragma mark - MessageCellDelegate
|
||||
|
@@ -7,7 +7,7 @@
|
||||
// 请注意,这是一次冒险。😱
|
||||
//
|
||||
|
||||
#import "BaseViewController.h"
|
||||
#import "MvpViewController.h"
|
||||
#import <JXCategoryView/JXCategoryListContainerView.h>
|
||||
#import <NIMSDK/NIMSDK.h>
|
||||
#import <JXPagingView/JXPagerView.h>
|
||||
@@ -19,7 +19,7 @@ typedef NS_ENUM(NSUInteger, SessionListOpenType) {
|
||||
SessionListOpenTypeRoom = 2,
|
||||
};
|
||||
|
||||
@interface SessionListViewController : BaseViewController<JXPagerViewListViewDelegate,JXCategoryListContentViewDelegate>
|
||||
@interface SessionListViewController : MvpViewController<JXPagerViewListViewDelegate,JXCategoryListContentViewDelegate>
|
||||
|
||||
- (instancetype)initWithType:(SessionListOpenType)type;
|
||||
/** 控制器 因为房间内聊天没有控制器去push 或者做其他的操作*/
|
||||
|
@@ -20,13 +20,14 @@
|
||||
#import "XPSessionFindNewViewController.h"
|
||||
#import "TTPopUp.h"
|
||||
#import "XPSkillCardPlayerManager.h"
|
||||
|
||||
#import "MessagePresenter.h"
|
||||
#import "MessageProtocol.h"
|
||||
|
||||
NSString * const kMessageShowReadDotKey = @"kMessageShowReadDotKey";
|
||||
|
||||
#import <Masonry/Masonry.h>
|
||||
|
||||
@interface SessionListViewController ()<UITableViewDataSource, UITableViewDelegate, NIMLoginManagerDelegate, NIMConversationManagerDelegate>
|
||||
@interface SessionListViewController ()<UITableViewDataSource, UITableViewDelegate, NIMLoginManagerDelegate, NIMConversationManagerDelegate, MessageProtocol>
|
||||
|
||||
/**
|
||||
* 会话列表
|
||||
@@ -42,6 +43,9 @@ NSString * const kMessageShowReadDotKey = @"kMessageShowReadDotKey";
|
||||
///用户信息
|
||||
@property (nonatomic,strong) UserInfoModel *userInfo;
|
||||
@property (nonatomic, copy) void(^scrollCallback)(UIScrollView *scrollView);
|
||||
|
||||
@property (nonatomic, strong) NIMRecentSession *recentSession;
|
||||
|
||||
@end
|
||||
|
||||
@implementation SessionListViewController
|
||||
@@ -56,6 +60,10 @@ NSString * const kMessageShowReadDotKey = @"kMessageShowReadDotKey";
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (MessagePresenter *)createPresenter {
|
||||
return [[MessagePresenter alloc] init];
|
||||
}
|
||||
|
||||
- (instancetype)initWithType:(SessionListOpenType)type {
|
||||
self = [self init];
|
||||
if (self) {
|
||||
@@ -137,6 +145,15 @@ NSString * const kMessageShowReadDotKey = @"kMessageShowReadDotKey";
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)onGetUserInfoSuccess:(UserInfoModel *)userInfo {
|
||||
if (userInfo) {
|
||||
SessionViewController *vc = [[SessionViewController alloc] initWithSession:self.recentSession.session];
|
||||
vc.openType = self.openType;
|
||||
vc.userInfo = userInfo;
|
||||
[self.navigationController pushViewController:vc animated:YES];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - UITableViewDelegate
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
|
||||
if (self.recentSessions.count == 0) {
|
||||
@@ -157,9 +174,14 @@ NSString * const kMessageShowReadDotKey = @"kMessageShowReadDotKey";
|
||||
[self.mainController addChildViewController:sessionVC];
|
||||
} else {
|
||||
NIMRecentSession *recentSession = self.recentSessions[indexPath.row];
|
||||
SessionViewController *vc = [[SessionViewController alloc] initWithSession:recentSession.session];
|
||||
vc.openType = self.openType;
|
||||
[self.navigationController pushViewController:vc animated:YES];
|
||||
self.recentSession = recentSession;
|
||||
if ([[[ClientConfig shareConfig].configInfo officialAccountUids] containsObject:self.recentSession.session.sessionId]) {
|
||||
SessionViewController *vc = [[SessionViewController alloc] initWithSession:self.recentSession.session];
|
||||
vc.openType = self.openType;
|
||||
[self.navigationController pushViewController:vc animated:YES];
|
||||
} else {
|
||||
[self.presenter getUserInfoWithUid:recentSession.session.sessionId];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -15,8 +15,8 @@
|
||||
return YMLocalizedString(@"20.20.61_text_9");
|
||||
}
|
||||
|
||||
// 将秒转换为 NSDate
|
||||
NSDate *expireDate = [NSDate dateWithTimeIntervalSince1970:self.expireSeconds];
|
||||
// 当前时间 + expireSeconds 得到目标时间
|
||||
NSDate *expireDate = [NSDate dateWithTimeIntervalSinceNow:self.expireSeconds];
|
||||
|
||||
// 创建日期格式化器
|
||||
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
|
||||
|
@@ -20,6 +20,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
//充值banner位数据
|
||||
@property(nonatomic,copy) NSString *bannerUrl;
|
||||
@property(nonatomic,copy) NSString *linkUrl;
|
||||
@property (nonatomic, assign) NSInteger chargeGoldNum;
|
||||
|
||||
@end
|
||||
|
||||
|
@@ -18,7 +18,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
@property(nonatomic, copy)NSString *diamonds;
|
||||
//金币数量
|
||||
@property(nonatomic, assign) double golds;
|
||||
@property(nonatomic, copy)NSString *chargeGoldNum;
|
||||
@property(nonatomic, copy) NSString *chargeGoldNum;
|
||||
|
||||
@property(nonatomic, assign)NSInteger amount;
|
||||
/// 钻石数量
|
||||
|
@@ -16,7 +16,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
- (void)userMedalsSuccess:(UserMedalsModel *)userMedalsModel;
|
||||
- (void)userMedalsFailure;
|
||||
|
||||
- (void)squareMedalsSuccess:(NSArray <MedalSeriesVo *> *)squareMedalsModel;
|
||||
- (void)squareMedalsSuccess:(NSArray <MedalSeriesItemVo *> *)squareMedalsModel;
|
||||
- (void)squareMedalsFailure;
|
||||
|
||||
- (void)mineAllMedalsSuccess:(MineAllMedalModel *)model;
|
||||
|
@@ -156,6 +156,7 @@
|
||||
}
|
||||
|
||||
- (void)setUserMedalModel:(UserMedalModel *)userMedalModel {
|
||||
_userMedalModel = userMedalModel;
|
||||
|
||||
self.icon.hidden = YES;
|
||||
self.vapView.hidden = NO;
|
||||
@@ -168,21 +169,99 @@
|
||||
}];
|
||||
|
||||
self.nameLabel.text = userMedalModel.medalName;
|
||||
if (self.videoUrl.length > 0) {
|
||||
[self.vapView playHWDMP4:self.videoUrl repeatCount:-1 delegate:nil];
|
||||
} else {
|
||||
NSString *resourcePath = [userMedalModel.picUrl pureURLString];
|
||||
if (resourcePath.length > 0) {
|
||||
@kWeakify(self);
|
||||
[self.vapParser parseWithURL:resourcePath completionBlock:^(NSString * _Nullable videoUrl) {
|
||||
@kStrongify(self);
|
||||
if (videoUrl.length) {
|
||||
[self.vapView playHWDMP4:videoUrl repeatCount:-1 delegate:nil];
|
||||
}
|
||||
} failureBlock:^(NSError * _Nullable error) {
|
||||
}];
|
||||
}
|
||||
|
||||
// 停止之前的播放
|
||||
[self.vapView stopHWDMP4];
|
||||
|
||||
// 按照新的优先级逻辑处理显示
|
||||
NSString *mp4Url = userMedalModel.mp4Url;
|
||||
NSString *picUrl = userMedalModel.picUrl;
|
||||
|
||||
// 1. 优先使用 mp4Url 展示 vapView 内容(判断是否有效 mp4)
|
||||
if (![NSString isEmpty:mp4Url] && [self isValidMP4URL:mp4Url]) {
|
||||
[self playMP4WithUrl:mp4Url];
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. mp4Url 无效,检查 picUrl 是否为有效图片
|
||||
if (![NSString isEmpty:picUrl] && [NSString isValidImageURL:picUrl]) {
|
||||
// 显示图片内容
|
||||
[self showImageWithUrl:picUrl];
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. picUrl 不是有效图片,尝试使用 picUrl 展示 vapView 内容
|
||||
if (![NSString isEmpty:picUrl]) {
|
||||
[self playMP4WithUrl:picUrl];
|
||||
return;
|
||||
}
|
||||
|
||||
// 所有条件都不满足,显示默认状态
|
||||
[self showDefaultState];
|
||||
}
|
||||
|
||||
#pragma mark - 私有方法
|
||||
|
||||
/// 验证是否为有效的 MP4 URL
|
||||
- (BOOL)isValidMP4URL:(NSString *)url {
|
||||
if ([NSString isEmpty:url]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
NSString *lowercaseUrl = [url lowercaseString];
|
||||
return [lowercaseUrl hasSuffix:@".mp4"] ||
|
||||
[lowercaseUrl containsString:@"mp4"] ||
|
||||
[lowercaseUrl containsString:@"video"];
|
||||
}
|
||||
|
||||
/// 验证是否为有效的图片 URL
|
||||
- (BOOL)isValidImageURL:(NSString *)url {
|
||||
if ([NSString isEmpty:url]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
NSString *lowercaseUrl = [url lowercaseString];
|
||||
return [lowercaseUrl hasSuffix:@".jpg"] ||
|
||||
[lowercaseUrl hasSuffix:@".jpeg"] ||
|
||||
[lowercaseUrl hasSuffix:@".png"] ||
|
||||
[lowercaseUrl hasSuffix:@".gif"] ||
|
||||
[lowercaseUrl hasSuffix:@".webp"] ||
|
||||
[lowercaseUrl containsString:@"image"];
|
||||
}
|
||||
|
||||
/// 播放 MP4 内容
|
||||
- (void)playMP4WithUrl:(NSString *)url {
|
||||
self.vapView.hidden = NO;
|
||||
self.icon.hidden = YES;
|
||||
|
||||
NSString *resourcePath = [url pureURLString];
|
||||
if (resourcePath.length > 0) {
|
||||
@kWeakify(self);
|
||||
[self.vapParser parseWithURL:resourcePath completionBlock:^(NSString * _Nullable videoUrl) {
|
||||
@kStrongify(self);
|
||||
if (videoUrl.length) {
|
||||
[self.vapView playHWDMP4:videoUrl repeatCount:-1 delegate:nil];
|
||||
}
|
||||
} failureBlock:^(NSError * _Nullable error) {
|
||||
@kStrongify(self);
|
||||
// MP4 播放失败,显示默认状态
|
||||
[self showDefaultState];
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
/// 显示图片内容
|
||||
- (void)showImageWithUrl:(NSString *)url {
|
||||
self.vapView.hidden = YES;
|
||||
self.icon.hidden = NO;
|
||||
self.icon.imageUrl = url;
|
||||
}
|
||||
|
||||
/// 显示默认状态
|
||||
- (void)showDefaultState {
|
||||
self.vapView.hidden = YES;
|
||||
self.icon.hidden = NO;
|
||||
self.icon.imageUrl = @""; // 显示默认占位图
|
||||
}
|
||||
|
||||
- (NetImageView *)icon {
|
||||
|
@@ -76,6 +76,7 @@
|
||||
- (void)handleTapFirstCharge {
|
||||
XPWebViewController *webVC = [[XPWebViewController alloc] initWithRoomUID:@""];
|
||||
webVC.url = URLWithType(kFirstChargeBanner);
|
||||
webVC.isPush = YES;
|
||||
[self.navigationController pushViewController:webVC animated:YES];
|
||||
}
|
||||
|
||||
|
@@ -6,7 +6,7 @@
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
@class MedalSeriesVo;
|
||||
@class MedalSeriesItemVo;
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface MedalsCollectionViewCell : UICollectionViewCell
|
||||
@@ -14,7 +14,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
+ (void)registerTo:(UICollectionView *)collectionView;
|
||||
+ (instancetype)cellFor:(UICollectionView *)collectionView atIndexPath:(NSIndexPath *)index;
|
||||
|
||||
- (void)updateCell:(MedalSeriesVo *)model;
|
||||
- (void)updateCell:(MedalSeriesItemVo *)model isForSquare:(BOOL)isSquare;
|
||||
|
||||
/**
|
||||
* 当 cell 将要显示时调用
|
||||
|
@@ -146,9 +146,12 @@
|
||||
// 停止播放
|
||||
[self stopMP4Playback];
|
||||
|
||||
// 隐藏 mp4 视图
|
||||
// 更彻底地重置 mp4View
|
||||
[self resetMP4View];
|
||||
|
||||
// 隐藏视图
|
||||
self.mp4View.hidden = YES;
|
||||
self.imageView.hidden = NO;
|
||||
self.imageView.hidden = YES;
|
||||
|
||||
// 重置状态
|
||||
self.mp4Path = nil;
|
||||
@@ -157,6 +160,7 @@
|
||||
self.displayModel = nil; // 重置数据模型
|
||||
self.currentItemVo = nil; // 重置当前项
|
||||
|
||||
|
||||
// 清空文本
|
||||
self.titleLabel.text = @"";
|
||||
self.subLabel.text = @"";
|
||||
@@ -169,27 +173,26 @@
|
||||
self.imageView.imageUrl = @"";
|
||||
}
|
||||
|
||||
- (void)updateCell:(MedalSeriesVo *)model {
|
||||
MedalSeriesItemVo *itemVos = [model.medalSeries xpSafeObjectAtIndex:0];
|
||||
self.currentItemVo = itemVos;
|
||||
self.displayModel = [itemVos.medalVos xpSafeObjectAtIndex:0];
|
||||
- (void)updateCell:(MedalSeriesItemVo *)model isForSquare:(BOOL)isSquare {
|
||||
// MedalSeriesItemVo *itemVos = [model.medalSeries xpSafeObjectAtIndex:0];
|
||||
self.currentItemVo = model;
|
||||
|
||||
// 配置等级指示器
|
||||
[self.levelIndicatorView setupWithMaxLevel:itemVos.medalLevel];
|
||||
[self.levelIndicatorView setSelectedLevel:1 animated:NO];
|
||||
|
||||
// 设置指示器类型为带图片
|
||||
// 设置指示器类型为不带图片
|
||||
self.levelIndicatorView.indicatorType = MedalsLevelIndicatorTypeNormal;
|
||||
|
||||
// 为每个等级设置对应的图片,使用新的 URL 优先级逻辑
|
||||
for (NSInteger i = 0; i < itemVos.medalVos.count; i++) {
|
||||
MedalVo *medalVo = [itemVos.medalVos xpSafeObjectAtIndex:i];
|
||||
if (medalVo) {
|
||||
NSString *imageUrl = [self getImageUrlForMedal:medalVo];
|
||||
[self.levelIndicatorView setImageUrl:imageUrl forLevel:i + 1];
|
||||
}
|
||||
// 配置等级指示器
|
||||
[self.levelIndicatorView setupWithMaxLevel:model.medalLevel];
|
||||
|
||||
if (isSquare) {
|
||||
self.displayModel = [model.medalVos xpSafeObjectAtIndex:model.medalVos.count - 1];
|
||||
[self.levelIndicatorView setSelectedLevel:model.medalLevel animated:NO];
|
||||
} else {
|
||||
self.displayModel = [model.medalVos xpSafeObjectAtIndex:0];
|
||||
[self.levelIndicatorView setSelectedLevel:1 animated:NO];
|
||||
}
|
||||
|
||||
self.levelIndicatorView.userInteractionEnabled = !isSquare;
|
||||
|
||||
[self updateDisplayWithCurrentModel];
|
||||
}
|
||||
|
||||
@@ -199,11 +202,9 @@
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: 要手动 fix mp4 不播放的问题
|
||||
|
||||
// 优化后的判断逻辑:更严格的 MP4 URL 验证
|
||||
NSString *mp4Url = self.currentItemVo.mp4Url;
|
||||
NSString *picUrl = self.currentItemVo.picUrl;
|
||||
NSString *mp4Url = self.displayModel.mp4Url;
|
||||
NSString *picUrl = self.displayModel.picUrl;
|
||||
|
||||
// 首先检查是否有明确的 MP4 URL
|
||||
if (![NSString isEmpty:mp4Url] && [self isValidMP4URL:mp4Url]) {
|
||||
@@ -229,8 +230,7 @@
|
||||
[self showDefaultPlaceholder];
|
||||
|
||||
// 设置文本信息(无论是否有有效的媒体内容都要设置)
|
||||
self.titleLabel.text = self.displayModel.name;
|
||||
self.subLabel.text = [self.displayModel expireDateString];
|
||||
[self updateTextLabels];
|
||||
}
|
||||
|
||||
#pragma mark - 私有方法
|
||||
@@ -296,6 +296,10 @@
|
||||
}
|
||||
|
||||
- (void)setImagePath:(NSString *)imagePath {
|
||||
if ([NSString isEmpty:imagePath]) {
|
||||
self.imageView.hidden = YES;
|
||||
return;
|
||||
}
|
||||
// 停止之前的 mp4 播放
|
||||
[self stopMP4Playback];
|
||||
|
||||
@@ -306,8 +310,8 @@
|
||||
}
|
||||
|
||||
- (void)setMp4Path:(NSString *)mp4Path {
|
||||
// 如果是相同的 mp4 路径,不需要重新加载
|
||||
if ([_mp4Path isEqualToString:mp4Path]) {
|
||||
if ([NSString isEmpty:mp4Path]) {
|
||||
self.mp4View.hidden = YES;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -366,6 +370,35 @@
|
||||
|
||||
#pragma mark - MP4 播放控制
|
||||
|
||||
/// 重置 MP4 视图,清理所有缓存内容
|
||||
- (void)resetMP4View {
|
||||
if (self.mp4View) {
|
||||
// 方案1: 基础重置(推荐)
|
||||
[self.mp4View stopHWDMP4];
|
||||
self.mp4View.tag = 0;
|
||||
self.mp4View.hidden = YES;
|
||||
|
||||
// 方案2: 完全重置(如果遇到严重的缓存问题才启用)
|
||||
if (YES) { // 根据需要设置为 NO 来禁用完全重置
|
||||
[self.mp4View removeFromSuperview];
|
||||
_mp4View = nil;
|
||||
// 重新添加 mp4View
|
||||
[self.contentView addSubview:self.mp4View];
|
||||
[self.mp4View mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.edges.mas_equalTo(self.imageView);
|
||||
}];
|
||||
}
|
||||
|
||||
// 方案3: 强制清理内存(备用方案)
|
||||
// 通过设置新的frame来触发内部清理
|
||||
if (NO) { // 可以启用此方案作为替代
|
||||
CGRect currentFrame = self.mp4View.frame;
|
||||
self.mp4View.frame = CGRectZero;
|
||||
self.mp4View.frame = currentFrame;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)stopMP4Playback {
|
||||
if (self.mp4View) {
|
||||
[self.mp4View stopHWDMP4];
|
||||
@@ -375,7 +408,7 @@
|
||||
|
||||
- (void)pauseMP4Playback {
|
||||
if (self.mp4View && !self.mp4View.hidden) {
|
||||
[self.mp4View pauseHWDMP4];
|
||||
[self.mp4View stopHWDMP4];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -404,6 +437,7 @@
|
||||
NSLog(@"%@", error);
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - HWDMP4PlayDelegate
|
||||
|
||||
- (BOOL)shouldStartPlayMP4:(VAPView *)container config:(QGVAPConfigModel *)config {
|
||||
@@ -428,6 +462,7 @@
|
||||
|
||||
- (void)willDisplay {
|
||||
self.isVisible = YES;
|
||||
// return;
|
||||
|
||||
// 如果有准备好的 MP4,立即开始播放
|
||||
if (self.mp4View.tag == 1 && !self.mp4View.hidden && self.mp4Path) {
|
||||
@@ -482,7 +517,8 @@
|
||||
- (VAPView *)mp4View {
|
||||
if (!_mp4View) {
|
||||
_mp4View = [[VAPView alloc] init];
|
||||
_mp4View.contentMode = UIViewContentModeScaleAspectFill;
|
||||
_mp4View.contentMode = UIViewContentModeScaleAspectFit;
|
||||
// [_mp4View enableOldVersion:YES];
|
||||
}
|
||||
return _mp4View;
|
||||
}
|
||||
|
@@ -0,0 +1,214 @@
|
||||
//
|
||||
// MedalsCollectionViewCell_Refactored.m
|
||||
// YuMi
|
||||
//
|
||||
// 重构示例:使用 MedalMediaDisplayManager 简化媒体处理逻辑
|
||||
//
|
||||
|
||||
#import "MedalsCollectionViewCell.h"
|
||||
#import "MedalsModel.h"
|
||||
#import "MedalMediaDisplayManager.h"
|
||||
#import "MedalsLevelIndicatorView.h"
|
||||
|
||||
@interface MedalsCollectionViewCell () <MedalMediaDisplayDelegate>
|
||||
|
||||
// 媒体显示管理器 - 替代原来的所有媒体相关属性和方法
|
||||
@property (nonatomic, strong) MedalMediaDisplayManager *mediaManager;
|
||||
|
||||
// UI 元素
|
||||
@property (nonatomic, strong) NetImageView *imageView;
|
||||
@property (nonatomic, strong) VAPView *mp4View;
|
||||
@property (nonatomic, strong) UILabel *titleLabel;
|
||||
@property (nonatomic, strong) UILabel *subLabel;
|
||||
@property (nonatomic, strong) MedalsLevelIndicatorView *levelIndicatorView;
|
||||
|
||||
// 数据模型
|
||||
@property (nonatomic, strong) MedalVo *displayModel;
|
||||
@property (nonatomic, strong) MedalSeriesItemVo *currentItemVo;
|
||||
|
||||
@end
|
||||
|
||||
@implementation MedalsCollectionViewCell
|
||||
|
||||
+ (NSString *)cellID {
|
||||
return NSStringFromClass([MedalsCollectionViewCell class]);
|
||||
}
|
||||
|
||||
+ (void)registerTo:(UICollectionView *)collectionView {
|
||||
[collectionView registerClass:[self class] forCellWithReuseIdentifier:[self cellID]];
|
||||
}
|
||||
|
||||
+ (instancetype)cellFor:(UICollectionView *)collectionView atIndexPath:(NSIndexPath *)index {
|
||||
MedalsCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:[self cellID]
|
||||
forIndexPath:index];
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
[self setupUI];
|
||||
[self setupMediaManager];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setupUI {
|
||||
// UI 设置保持不变
|
||||
[self.contentView addGradientBackgroundWithColors:@[
|
||||
UIColorFromRGB(0x41007b),
|
||||
UIColorFromRGB(0x290858)
|
||||
] startPoint:CGPointMake(0.5, 0) endPoint:CGPointMake(0.5, 1) cornerRadius:8];
|
||||
|
||||
[self.contentView setAllCornerRadius:8
|
||||
borderWidth:1
|
||||
borderColor:UIColorFromRGB(0xa166bf)];
|
||||
|
||||
self.imageView = [[NetImageView alloc] init];
|
||||
self.imageView.contentMode = UIViewContentModeScaleAspectFill;
|
||||
[self.contentView addSubview:self.imageView];
|
||||
[self.imageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.centerX.mas_equalTo(self.contentView);
|
||||
make.top.mas_equalTo(13);
|
||||
make.leading.trailing.mas_equalTo(self.contentView).inset(13);
|
||||
make.height.mas_equalTo(self.imageView.mas_width);
|
||||
}];
|
||||
|
||||
self.mp4View = [[VAPView alloc] init];
|
||||
self.mp4View.contentMode = UIViewContentModeScaleAspectFit;
|
||||
[self.contentView addSubview:self.mp4View];
|
||||
[self.mp4View mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.edges.mas_equalTo(self.imageView);
|
||||
}];
|
||||
|
||||
// 其他UI元素设置...
|
||||
self.titleLabel = [UILabel labelInitWithText:@"" font:kFontMedium(14) textColor:[UIColor whiteColor]];
|
||||
self.subLabel = [UILabel labelInitWithText:@"" font:kFontRegular(11) textColor:[UIColor colorWithWhite:1 alpha:0.6]];
|
||||
// ... 约束设置省略
|
||||
}
|
||||
|
||||
- (void)setupMediaManager {
|
||||
// 创建媒体管理器,传入自己作为代理
|
||||
self.mediaManager = [[MedalMediaDisplayManager alloc] initWithDelegate:self];
|
||||
}
|
||||
|
||||
- (void)prepareForReuse {
|
||||
[super prepareForReuse];
|
||||
|
||||
// 使用媒体管理器清理资源 - 替代原来的复杂清理逻辑
|
||||
[self.mediaManager cleanupResources];
|
||||
|
||||
// 重置UI状态
|
||||
self.displayModel = nil;
|
||||
self.currentItemVo = nil;
|
||||
self.titleLabel.text = @"";
|
||||
self.subLabel.text = @"";
|
||||
[self.levelIndicatorView resetToLevel:0];
|
||||
}
|
||||
|
||||
- (void)updateCell:(MedalSeriesVo *)model isForSquare:(BOOL)isSquare {
|
||||
MedalSeriesItemVo *itemVos = [model.medalSeries xpSafeObjectAtIndex:0];
|
||||
self.currentItemVo = itemVos;
|
||||
|
||||
// 设置等级指示器
|
||||
self.levelIndicatorView.indicatorType = MedalsLevelIndicatorTypeNormal;
|
||||
[self.levelIndicatorView setupWithMaxLevel:itemVos.medalLevel];
|
||||
|
||||
if (isSquare) {
|
||||
self.displayModel = [itemVos.medalVos xpSafeObjectAtIndex:itemVos.medalVos.count - 1];
|
||||
[self.levelIndicatorView setSelectedLevel:itemVos.medalLevel animated:NO];
|
||||
} else {
|
||||
self.displayModel = [itemVos.medalVos xpSafeObjectAtIndex:0];
|
||||
[self.levelIndicatorView setSelectedLevel:1 animated:NO];
|
||||
}
|
||||
|
||||
self.levelIndicatorView.userInteractionEnabled = !isSquare;
|
||||
|
||||
// 使用媒体管理器更新显示 - 替代原来的复杂逻辑
|
||||
[self.mediaManager updateDisplayWithModel:self.displayModel];
|
||||
|
||||
// 更新文本信息
|
||||
[self updateTextLabels];
|
||||
}
|
||||
|
||||
- (void)updateTextLabels {
|
||||
self.titleLabel.text = self.displayModel.name;
|
||||
self.subLabel.text = [self.displayModel expireDateString];
|
||||
}
|
||||
|
||||
#pragma mark - 可见性管理 - 大幅简化
|
||||
|
||||
- (void)willDisplay {
|
||||
[self.mediaManager willDisplay];
|
||||
}
|
||||
|
||||
- (void)didEndDisplaying {
|
||||
[self.mediaManager didEndDisplaying];
|
||||
}
|
||||
|
||||
#pragma mark - MedalMediaDisplayDelegate - 核心代理方法
|
||||
|
||||
- (NSString *)getMP4UrlFromModel:(id)model {
|
||||
MedalVo *medalVo = (MedalVo *)model;
|
||||
return medalVo.mp4Url;
|
||||
}
|
||||
|
||||
- (NSString *)getPicUrlFromModel:(id)model {
|
||||
MedalVo *medalVo = (MedalVo *)model;
|
||||
return medalVo.picUrl;
|
||||
}
|
||||
|
||||
- (NetImageView *)getImageView {
|
||||
return self.imageView;
|
||||
}
|
||||
|
||||
- (VAPView *)getMP4View {
|
||||
return self.mp4View;
|
||||
}
|
||||
|
||||
- (void)onMediaDisplayUpdated:(BOOL)isMP4 success:(BOOL)success {
|
||||
// 可选:处理媒体显示状态更新
|
||||
NSLog(@"Media display updated: %@ - %@", isMP4 ? @"MP4" : @"Image", success ? @"Success" : @"Failed");
|
||||
}
|
||||
|
||||
- (UIImage *)getDefaultPlaceholderImage {
|
||||
return [UIImageConstant defaultEmptyPlaceholder];
|
||||
}
|
||||
|
||||
#pragma mark - 生命周期
|
||||
|
||||
- (void)dealloc {
|
||||
// 媒体管理器会自动处理资源清理
|
||||
NSLog(@"MedalsCollectionViewCell dealloc");
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
/*
|
||||
重构效果对比:
|
||||
|
||||
原始代码:~528行
|
||||
重构后代码:~150行(减少70%+)
|
||||
|
||||
移除的重复代码:
|
||||
- 所有媒体路径属性和管理逻辑
|
||||
- MP4播放器相关属性和方法
|
||||
- 复杂的播放状态管理
|
||||
- 应用生命周期通知处理
|
||||
- MP4解析和播放控制逻辑
|
||||
- 失败降级处理逻辑
|
||||
- 可见性管理的复杂逻辑
|
||||
|
||||
保留的业务逻辑:
|
||||
- UI布局和样式
|
||||
- 等级指示器相关逻辑
|
||||
- 业务数据模型处理
|
||||
- 特定的UI更新逻辑
|
||||
|
||||
核心优势:
|
||||
1. 代码量大幅减少,可读性提升
|
||||
2. 媒体处理逻辑统一管理
|
||||
3. Bug修复只需要在一个地方
|
||||
4. 新功能添加更容易
|
||||
5. 测试和维护成本降低
|
||||
*/
|
@@ -91,9 +91,12 @@
|
||||
// 停止播放
|
||||
[self stopMP4Playback];
|
||||
|
||||
// 隐藏 mp4 视图
|
||||
// 更彻底地重置 mp4View
|
||||
[self resetMP4View];
|
||||
|
||||
// 隐藏视图
|
||||
self.mp4View.hidden = YES;
|
||||
self.imageView.hidden = NO;
|
||||
self.imageView.hidden = YES;
|
||||
|
||||
// 重置状态
|
||||
self.mp4Path = nil;
|
||||
@@ -179,10 +182,15 @@
|
||||
}
|
||||
|
||||
- (void)setMp4Path:(NSString *)mp4Path {
|
||||
// 如果是相同的 mp4 路径,不需要重新加载
|
||||
if ([_mp4Path isEqualToString:mp4Path]) {
|
||||
if ([NSString isEmpty:mp4Path]) {
|
||||
self.mp4View.hidden = YES;
|
||||
[self handleMP4FailureWithFallback];
|
||||
return;
|
||||
}
|
||||
// 如果是相同的 mp4 路径,不需要重新加载
|
||||
// if ([_mp4Path isEqualToString:mp4Path]) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// 停止之前的 mp4 播放
|
||||
[self stopMP4Playback];
|
||||
@@ -239,6 +247,35 @@
|
||||
|
||||
#pragma mark - MP4 播放控制
|
||||
|
||||
/// 重置 MP4 视图,清理所有缓存内容
|
||||
- (void)resetMP4View {
|
||||
if (self.mp4View) {
|
||||
// 方案1: 基础重置(推荐)
|
||||
[self.mp4View stopHWDMP4];
|
||||
self.mp4View.tag = 0;
|
||||
self.mp4View.hidden = YES;
|
||||
|
||||
// 方案2: 完全重置(如果遇到严重的缓存问题才启用)
|
||||
if (NO) { // 根据需要设置为 NO 来禁用完全重置
|
||||
[self.mp4View removeFromSuperview];
|
||||
_mp4View = nil;
|
||||
// 重新添加 mp4View
|
||||
[self.contentView addSubview:self.mp4View];
|
||||
[self.mp4View mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.edges.mas_equalTo(self.imageView);
|
||||
}];
|
||||
}
|
||||
|
||||
// 方案3: 强制清理内存(备用方案)
|
||||
// 通过设置新的frame来触发内部清理
|
||||
if (NO) { // 可以启用此方案作为替代
|
||||
CGRect currentFrame = self.mp4View.frame;
|
||||
self.mp4View.frame = CGRectZero;
|
||||
self.mp4View.frame = currentFrame;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)stopMP4Playback {
|
||||
if (self.mp4View) {
|
||||
[self.mp4View stopHWDMP4];
|
||||
@@ -246,44 +283,33 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)pauseMP4Playback {
|
||||
if (self.mp4View && !self.mp4View.hidden) {
|
||||
[self.mp4View pauseHWDMP4];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)resumeMP4Playback {
|
||||
if (self.mp4View && !self.mp4View.hidden && self.mp4Path) {
|
||||
if (self.mp4View.tag == 1) { // 已准备好但尚未播放
|
||||
@kWeakify(self);
|
||||
[self.mp4Parser parseWithURL:self.mp4Path
|
||||
completionBlock:^(NSString * _Nullable videoUrl) {
|
||||
@kStrongify(self);
|
||||
if (![NSString isEmpty:videoUrl] && self.isVisible) {
|
||||
[self startMP4PlaybackWithURL:videoUrl];
|
||||
}
|
||||
} failureBlock:^(NSError * _Nullable error) {
|
||||
@kStrongify(self);
|
||||
// MP4 恢复播放失败,降级使用 picURL
|
||||
[self handleMP4FailureWithFallback];
|
||||
}];
|
||||
} else {
|
||||
[self.mp4View resumeHWDMP4];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - 可见性管理
|
||||
|
||||
- (void)willDisplay {
|
||||
self.isVisible = YES;
|
||||
|
||||
// 如果有准备好的 MP4,立即开始播放
|
||||
if (self.mp4View.tag == 1 && !self.mp4View.hidden && self.mp4Path) {
|
||||
[self resumeMP4Playback];
|
||||
} else if (!self.mp4View.hidden) {
|
||||
// 恢复之前暂停的播放
|
||||
[self resumeMP4Playback];
|
||||
// 重新开始播放,而不是恢复暂停的播放
|
||||
if (!self.mp4View.hidden && self.mp4Path) {
|
||||
// 彻底停止当前播放
|
||||
[self stopMP4Playback];
|
||||
|
||||
// 重新开始播放
|
||||
if (!_mp4Parser) {
|
||||
self.mp4Parser = [[XPRoomGiftAnimationParser alloc] init];
|
||||
}
|
||||
|
||||
@kWeakify(self);
|
||||
[self.mp4Parser parseWithURL:self.mp4Path
|
||||
completionBlock:^(NSString * _Nullable videoUrl) {
|
||||
@kStrongify(self);
|
||||
if (![NSString isEmpty:videoUrl] && self.isVisible) {
|
||||
[self startMP4PlaybackWithURL:videoUrl];
|
||||
}
|
||||
} failureBlock:^(NSError * _Nullable error) {
|
||||
@kStrongify(self);
|
||||
NSLog(@"[MedalsCyclePagerCell] Failed to restart mp4 in willDisplay: %@", error);
|
||||
[self handleMP4FailureWithFallback];
|
||||
}];
|
||||
}
|
||||
|
||||
NSLog(@"[MedalsCyclePagerCell] willDisplay - isVisible: %@, mp4Path: %@",
|
||||
@@ -292,18 +318,34 @@
|
||||
|
||||
- (void)didEndDisplaying {
|
||||
self.isVisible = NO;
|
||||
[self pauseMP4Playback];
|
||||
// 彻底停止播放,而不是暂停
|
||||
[self stopMP4Playback];
|
||||
}
|
||||
|
||||
#pragma mark - 通知处理
|
||||
|
||||
- (void)appDidEnterBackground {
|
||||
[self pauseMP4Playback];
|
||||
[self stopMP4Playback];
|
||||
}
|
||||
|
||||
- (void)appWillEnterForeground {
|
||||
if (self.isVisible) {
|
||||
[self resumeMP4Playback];
|
||||
if (self.isVisible && !self.mp4View.hidden && self.mp4Path) {
|
||||
// 重新开始播放
|
||||
if (!_mp4Parser) {
|
||||
self.mp4Parser = [[XPRoomGiftAnimationParser alloc] init];
|
||||
}
|
||||
|
||||
@kWeakify(self);
|
||||
[self.mp4Parser parseWithURL:self.mp4Path
|
||||
completionBlock:^(NSString * _Nullable videoUrl) {
|
||||
@kStrongify(self);
|
||||
if (![NSString isEmpty:videoUrl] && self.isVisible) {
|
||||
[self startMP4PlaybackWithURL:videoUrl];
|
||||
}
|
||||
} failureBlock:^(NSError * _Nullable error) {
|
||||
@kStrongify(self);
|
||||
[self handleMP4FailureWithFallback];
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -334,9 +376,7 @@
|
||||
if (!_mp4View) {
|
||||
_mp4View = [[VAPView alloc] init];
|
||||
_mp4View.contentMode = UIViewContentModeScaleAspectFit;
|
||||
#if DEBUG
|
||||
_mp4View.backgroundColor = [UIColor redColor];
|
||||
#endif
|
||||
// [_mp4View enableOldVersion:YES];
|
||||
}
|
||||
return _mp4View;
|
||||
}
|
||||
|
@@ -6,12 +6,12 @@
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
@class MedalSeriesVo;
|
||||
@class MedalSeriesItemVo;
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface MedalsDetailView : UIView
|
||||
|
||||
@property (nonatomic, strong) MedalSeriesVo *detailItemVo;
|
||||
@property (nonatomic, strong) MedalSeriesItemVo *detailItemVo;
|
||||
|
||||
@end
|
||||
|
||||
|
@@ -72,6 +72,7 @@
|
||||
make.centerX.mas_equalTo(self);
|
||||
make.top.mas_equalTo(self.imageView.mas_bottom).offset(8);
|
||||
make.leading.trailing.mas_equalTo(self).inset(13);
|
||||
make.height.mas_equalTo(28);
|
||||
}];
|
||||
[self addSubview:self.subLabel];
|
||||
[self.subLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
@@ -85,7 +86,7 @@
|
||||
[self addSubview:self.levelIndicatorView];
|
||||
[self.levelIndicatorView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.centerX.mas_equalTo(self);
|
||||
make.top.mas_equalTo(self.subLabel).offset(24);
|
||||
make.top.mas_equalTo(self.subLabel.mas_bottom).offset(33);
|
||||
make.leading.trailing.mas_greaterThanOrEqualTo(self).inset(8);
|
||||
make.height.mas_equalTo(66);
|
||||
}];
|
||||
@@ -116,27 +117,34 @@
|
||||
// 添加点击手势到关闭按钮区域
|
||||
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleBackgroundTap:)];
|
||||
[closeButtonView addGestureRecognizer:tapGesture];
|
||||
|
||||
UIButton *back = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[back setBackgroundImage:kImage(@"common_nav_back_white") forState:UIControlStateNormal];
|
||||
[back addTarget:selfWeak action:@selector(handleBackgroundTap:) forControlEvents:UIControlEventTouchUpInside];
|
||||
[self addSubview:back];
|
||||
[back mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.leading.mas_equalTo(16);
|
||||
make.top.mas_equalTo(kStatusBarHeight);
|
||||
make.size.mas_equalTo(CGSizeMake(22, 22));
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)setDetailItemVo:(MedalSeriesVo *)detailItemVo {
|
||||
_detailItemVo = detailItemVo;
|
||||
self.currentSeriesItemVO = [detailItemVo.medalSeries xpSafeObjectAtIndex:0];
|
||||
self.displayModel = [self.currentSeriesItemVO.medalVos xpSafeObjectAtIndex:0];
|
||||
- (void)setDetailItemVo:(MedalSeriesItemVo *)detailItemVo {
|
||||
// _detailItemVo = detailItemVo;
|
||||
self.currentSeriesItemVO = detailItemVo;
|
||||
self.displayModel = [detailItemVo.medalVos xpSafeObjectAtIndex:0];
|
||||
|
||||
[self.levelIndicatorView setupWithMaxLevel:self.currentSeriesItemVO.medalLevel];
|
||||
[self.levelIndicatorView setSelectedLevel:1 animated:NO];
|
||||
[self.levelIndicatorView setSeriesItems:detailItemVo.medalSeries];
|
||||
[self.levelIndicatorView setSeriesItems:detailItemVo.medalVos];
|
||||
|
||||
// 设置指示器类型为带图片
|
||||
self.levelIndicatorView.indicatorType = MedalsLevelIndicatorTypeWithImage;
|
||||
|
||||
// 为每个等级设置对应的图片,使用新的 URL 优先级逻辑
|
||||
for (NSInteger i = 0; i < self.currentSeriesItemVO.medalVos.count; i++) {
|
||||
MedalVo *medalVo = [self.currentSeriesItemVO.medalVos xpSafeObjectAtIndex:i];
|
||||
if (medalVo) {
|
||||
NSString *imageUrl = [self getImageUrlForMedal:medalVo];
|
||||
[self.levelIndicatorView setImageUrl:imageUrl forLevel:i + 1];
|
||||
}
|
||||
for (MedalVo *medalVo in detailItemVo.medalVos) {
|
||||
NSString *imageUrl = [self getImageUrlForMedal:medalVo];
|
||||
[self.levelIndicatorView setImageUrl:imageUrl forLevel:medalVo.level];
|
||||
}
|
||||
|
||||
[self updateDisplayWithCurrentModel];
|
||||
|
@@ -6,7 +6,7 @@
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
@class MedalSeriesItemVo;
|
||||
@class MedalSeriesItemVo, MedalVo;
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef NS_ENUM(NSInteger, MedalsLevelIndicatorType) {
|
||||
@@ -18,7 +18,7 @@ typedef NS_ENUM(NSInteger, MedalsLevelIndicatorType) {
|
||||
|
||||
@property (nonatomic, copy) void (^levelSelectedBlock)(NSInteger level);
|
||||
@property (nonatomic, assign) MedalsLevelIndicatorType indicatorType;
|
||||
@property (nonatomic, copy) NSArray <MedalSeriesItemVo *> *seriesItems;
|
||||
@property (nonatomic, copy) NSArray <MedalVo *> *seriesItems;
|
||||
|
||||
- (void)setupWithMaxLevel:(NSInteger)maxLevel;
|
||||
- (void)setSelectedLevel:(NSInteger)level animated:(BOOL)animated;
|
||||
@@ -40,7 +40,7 @@ typedef NS_ENUM(NSInteger, MedalsLevelIndicatorType) {
|
||||
* 设置系列数据,用于处理 MP4 和 PNG 资源
|
||||
* @param seriesItems MedalSeriesItemVo 数组
|
||||
*/
|
||||
- (void)setSeriesItems:(NSArray <MedalSeriesItemVo *> *)seriesItems;
|
||||
- (void)setSeriesItems:(NSArray <MedalVo *> *)seriesItems;
|
||||
|
||||
@end
|
||||
|
||||
|
@@ -610,25 +610,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setSeriesItems:(NSArray <MedalSeriesItemVo *> *)seriesItems {
|
||||
- (void)setSeriesItems:(NSArray <MedalVo *> *)seriesItems {
|
||||
_seriesItems = seriesItems;
|
||||
|
||||
// 如果没有系列数据或者等级指示器还没有创建,直接返回
|
||||
if (!seriesItems || seriesItems.count == 0 || _levelItems.count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取第一个系列项
|
||||
MedalSeriesItemVo *firstSeriesItem = [seriesItems xpSafeObjectAtIndex:0];
|
||||
if (!firstSeriesItem || !firstSeriesItem.medalVos) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 为每个等级设置对应的图片/MP4
|
||||
for (NSInteger i = 0; i < firstSeriesItem.medalVos.count && i < _levelItems.count; i++) {
|
||||
MedalVo *medalVo = [firstSeriesItem.medalVos xpSafeObjectAtIndex:i];
|
||||
|
||||
for (MedalVo *medalVo in seriesItems) {
|
||||
if (medalVo && medalVo.picUrl) {
|
||||
[self setImageUrl:medalVo.picUrl forLevel:i + 1];
|
||||
[self setImageUrl:medalVo.picUrl forLevel:medalVo.level];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -17,7 +17,7 @@
|
||||
@property (nonatomic, strong) NetImageView *avatarImageView;
|
||||
@property (nonatomic, strong) UILabel *nameLabel;
|
||||
@property (nonatomic, strong) UILabel *countLabel;
|
||||
|
||||
@property (nonatomic, strong) UILabel *detailLabel;
|
||||
|
||||
+ (void)registerTo:(UITableView *)tableView;
|
||||
+ (instancetype)cellFor:(UITableView *)tableView atIndexPath:(NSIndexPath *)index;
|
||||
@@ -46,6 +46,7 @@
|
||||
self.nameLabel.text = userModel.nick;
|
||||
self.indexLabel.text = @(userModel.rank).stringValue;
|
||||
self.countLabel.text = @(userModel.medalCount).stringValue;
|
||||
// self.detailLabel.hidden = userModel.uid == 0;
|
||||
}
|
||||
|
||||
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
|
||||
@@ -80,12 +81,12 @@
|
||||
make.top.mas_equalTo(self.avatarImageView);
|
||||
}];
|
||||
|
||||
UIImageView *rankIcon = [[UIImageView alloc] initWithImage:kImage(@"medals_rank")];
|
||||
UIImageView *rankIcon = [[UIImageView alloc] initWithImage:[kImage(@"medals_icon_rank") ms_SetImageForRTL]];
|
||||
[self.contentView addSubview:rankIcon];
|
||||
[rankIcon mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.leading.mas_equalTo(self.avatarImageView.mas_trailing).offset(6);
|
||||
make.bottom.mas_equalTo(self.avatarImageView);
|
||||
make.size.mas_equalTo(CGSizeMake(10, 14));
|
||||
make.size.mas_equalTo(CGSizeMake(15, 15));
|
||||
}];
|
||||
|
||||
self.countLabel = [UILabel labelInitWithText:@"" font:kFontMedium(14) textColor:[UIColor whiteColor]];
|
||||
@@ -95,11 +96,11 @@
|
||||
make.centerY.mas_equalTo(rankIcon);
|
||||
}];
|
||||
|
||||
UILabel *detailLabel = [UILabel labelInitWithText:YMLocalizedString(@"20.20.61_text_13")
|
||||
self.detailLabel = [UILabel labelInitWithText:YMLocalizedString(@"20.20.61_text_13")
|
||||
font:kFontRegular(12)
|
||||
textColor:[UIColor colorWithWhite:1 alpha:0.6]];
|
||||
[self.contentView addSubview:detailLabel];
|
||||
[detailLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
[self.contentView addSubview:self.detailLabel];
|
||||
[self.detailLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.trailing.mas_equalTo(self.contentView).offset(-28);
|
||||
make.centerY.mas_equalTo(self.contentView);
|
||||
}];
|
||||
@@ -175,13 +176,16 @@
|
||||
nameLabel = [UILabel labelInitWithText:@"" font:kFontSemibold(15) textColor:UIColorFromRGB(0xffffff)];
|
||||
[self addSubview:nameLabel];
|
||||
|
||||
medalIconImageView = [[UIImageView alloc] initWithImage:kImage(@"medals_rank")];
|
||||
medalIconImageView = [[UIImageView alloc] initWithImage:kImage(@"medals_icon_rank")];
|
||||
medalCountLabel = [UILabel labelInitWithText:@"0" font:kFontMedium(14) textColor:UIColorFromRGB(0xffffff)];
|
||||
medalCountStack = [[UIStackView alloc] initWithArrangedSubviews:@[
|
||||
medalIconImageView,
|
||||
medalCountLabel
|
||||
]];
|
||||
[self addSubview:medalCountStack];
|
||||
[medalIconImageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.size.mas_equalTo(CGSizeMake(15, 15));
|
||||
}];
|
||||
|
||||
honorLabel.hidden = YES;
|
||||
honorImageView.hidden = YES;
|
||||
@@ -349,7 +353,7 @@
|
||||
|
||||
- (void)setupRankList {
|
||||
[self.view addSubview:self.rankTableView];
|
||||
CGFloat height = 84 + kSafeAreaBottomHeight;
|
||||
CGFloat height = 84;
|
||||
[self.rankTableView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.mas_equalTo(self.topTwo.mas_bottom).offset(40);
|
||||
make.bottom.mas_equalTo(self.view).offset(-height);
|
||||
@@ -421,6 +425,8 @@
|
||||
self.countLabel.text = @(self.mineRankModel.medalCount).stringValue;
|
||||
|
||||
self.rankList = [NSMutableArray array];
|
||||
NSInteger currentRank = 4; // 从第4名开始计算(前三名已经处理)
|
||||
|
||||
for (MedalsRankUserModel *user in model.rankList) {
|
||||
if (user.rank == 1) {
|
||||
self.topOne.userModel = user;
|
||||
@@ -430,8 +436,23 @@
|
||||
self.topThree.userModel = user;
|
||||
} else {
|
||||
[self.rankList addObject:user];
|
||||
currentRank = MAX(currentRank, user.rank + 1);
|
||||
}
|
||||
}
|
||||
|
||||
// 补充数据至 10 个(rankList 中应有 7 个,因为前三名在 top 视图中)
|
||||
NSInteger targetCount = 7; // 总共10个,减去前3名
|
||||
while (self.rankList.count < targetCount) {
|
||||
MedalsRankUserModel *emptyUser = [[MedalsRankUserModel alloc] init];
|
||||
emptyUser.rank = currentRank;
|
||||
emptyUser.uid = 0;
|
||||
emptyUser.avatar = @"";
|
||||
emptyUser.nick = @"--";
|
||||
emptyUser.medalCount = 0;
|
||||
[self.rankList addObject:emptyUser];
|
||||
currentRank++;
|
||||
}
|
||||
|
||||
[self.rankTableView reloadData];
|
||||
}
|
||||
}
|
||||
@@ -461,11 +482,15 @@
|
||||
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
||||
|
||||
MedalsRankUserModel *model = [self.rankList xpSafeObjectAtIndex:indexPath.row];
|
||||
[self handleTopViewTap:model];
|
||||
|
||||
// 检查是否为有效的用户数据(非空补充数据)
|
||||
if (model && model.uid != 0) {
|
||||
[self handleTopViewTap:model];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)handleTopViewTap:(MedalsRankUserModel *)model {
|
||||
if (model) {
|
||||
if (model && model.uid != 0) {
|
||||
UserInfoModel *userInfo = [[UserInfoModel alloc] init];
|
||||
userInfo.uid = model.uid;
|
||||
userInfo.avatar = model.avatar;
|
||||
|
@@ -38,10 +38,11 @@ typedef enum : NSInteger {
|
||||
@property (nonatomic, strong) TYCyclePagerView *medalsCyclePagerView;
|
||||
@property (nonatomic, strong) UIView *emptyView;
|
||||
@property (nonatomic, copy) UICollectionView *medalsCollectionView;
|
||||
@property (nonatomic, strong) UIStackView *centerTabsStackView;
|
||||
|
||||
@property (nonatomic, strong) NSMutableArray <MedalSeriesVo *>*datasourceTaskMedals;
|
||||
@property (nonatomic, strong) NSMutableArray <MedalSeriesVo *>*datasourceActivityMedals;
|
||||
@property (nonatomic, strong) NSMutableArray <MedalSeriesVo *>*datasourceGloryMedals;
|
||||
@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;
|
||||
@@ -52,7 +53,9 @@ typedef enum : NSInteger {
|
||||
@property (nonatomic, assign) MedalsCenterDisplayType displayType;
|
||||
|
||||
@property (nonatomic, strong) UserMedalsModel *userMedalsModel;
|
||||
@property (nonatomic, copy) NSMutableArray <MedalSeriesVo *>*squareMedalVo;
|
||||
@property (nonatomic, copy) NSMutableArray <MedalSeriesVo *>*taskSquareMedalVo;
|
||||
@property (nonatomic, copy) NSMutableArray <MedalSeriesVo *>*activitySquareMedalVo;
|
||||
@property (nonatomic, copy) NSMutableArray <MedalSeriesVo *>*glorySquareMedalVo;
|
||||
|
||||
@property (nonatomic, strong) UIImageView *otherBG;
|
||||
@property (nonatomic, strong) NetImageView *otherAvatar;
|
||||
@@ -238,7 +241,7 @@ typedef enum : NSInteger {
|
||||
|
||||
[self setupNavigationBar];
|
||||
|
||||
if (self.displayType != MedalsCenterDisplayType_Other) {
|
||||
if (self.displayType == MedalsCenterDisplayType_Mine) {
|
||||
[self setupWearingButton];
|
||||
}
|
||||
}
|
||||
@@ -322,12 +325,12 @@ typedef enum : NSInteger {
|
||||
make.top.mas_equalTo(self.otherAvatar);
|
||||
}];
|
||||
|
||||
UIImageView *rankIcon = [[UIImageView alloc] initWithImage:kImage(@"medals_rank")];
|
||||
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(14, 18));
|
||||
make.size.mas_equalTo(CGSizeMake(22, 22));
|
||||
}];
|
||||
|
||||
self.otherCountLabel = [UILabel labelInitWithText:@""
|
||||
@@ -339,12 +342,12 @@ typedef enum : NSInteger {
|
||||
make.centerY.mas_equalTo(rankIcon);
|
||||
}];
|
||||
|
||||
self.otherMedal = [[NetImageView alloc] initWithImage:kImage(@"medals_empty")];
|
||||
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(80, 80));
|
||||
make.size.mas_equalTo(CGSizeMake(81, 81));
|
||||
}];
|
||||
|
||||
[self.view addSubview:self.otherMP4View];
|
||||
@@ -356,9 +359,9 @@ typedef enum : NSInteger {
|
||||
}
|
||||
|
||||
- (void)setupCenterTabs {
|
||||
UIStackView *centerTabsStackView = [self centerTabStack];
|
||||
[self.view addSubview:centerTabsStackView];
|
||||
[centerTabsStackView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
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 {
|
||||
@@ -384,10 +387,11 @@ typedef enum : NSInteger {
|
||||
[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, -15, 0, -25));
|
||||
make.edges.mas_equalTo(wearingButton).insets(UIEdgeInsetsMake(0, -25, 0, -25));
|
||||
}];
|
||||
}
|
||||
|
||||
@@ -445,11 +449,7 @@ typedef enum : NSInteger {
|
||||
[self.medalsCollectionView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.bottom.mas_equalTo(self.view);
|
||||
make.trailing.leading.mas_equalTo(self.view).inset(26);
|
||||
if (self.displayType == MedalsCenterDisplayType_Other) {
|
||||
make.height.mas_equalTo(kGetScaleWidth(500));
|
||||
} else {
|
||||
make.height.mas_equalTo(kGetScaleWidth(380));
|
||||
}
|
||||
make.top.mas_equalTo(self.centerTabsStackView.mas_bottom).offset(68);
|
||||
}];
|
||||
|
||||
// 添加下拉刷新
|
||||
@@ -583,6 +583,32 @@ typedef enum : NSInteger {
|
||||
}
|
||||
|
||||
- (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];
|
||||
@@ -622,24 +648,25 @@ typedef enum : NSInteger {
|
||||
NSMutableArray *editArr = [NSMutableArray array];
|
||||
switch (self.currentTabType) {
|
||||
case MedalsCenterTab_TaskMedals:
|
||||
arr = self.datasourceTaskMedals.copy;
|
||||
arr = self.taskSquareMedalVo.copy;
|
||||
break;
|
||||
case MedalsCenterTab_ActivityMedals:
|
||||
arr = self.datasourceActivityMedals.copy;
|
||||
arr = self.activitySquareMedalVo.copy;
|
||||
break;
|
||||
case MedalsCenterTab_GloryMedals:
|
||||
arr = self.datasourceGloryMedals.copy;
|
||||
arr = self.glorySquareMedalVo.copy;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
for (MedalSeriesVo *seriesVO in arr) {
|
||||
MedalSeriesItemVo *item = [seriesVO.medalSeries xpSafeObjectAtIndex:0];
|
||||
if (item) {
|
||||
MedalVo *medal = [item.medalVos xpSafeObjectAtIndex:0];
|
||||
if (medal) {
|
||||
[editArr addObject:medal];
|
||||
for (MedalSeriesItemVo *item in seriesVO.medalSeries) {
|
||||
// 遍历所有medalSeries,找到最高级别的
|
||||
for (MedalVo *medalVo in item.medalVos) {
|
||||
if (medalVo.level == item.medalLevel) {
|
||||
[editArr addObject:medalVo];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -651,7 +678,7 @@ typedef enum : NSInteger {
|
||||
self.emptyUserMedalButton.hidden = YES;
|
||||
self.medalsCyclePagerView.hidden = NO;
|
||||
[self.medalsCyclePagerView reloadData];
|
||||
if (self.useMedals.count > 1 && self.displayType == MedalsCenterDisplayType_Square) {
|
||||
if (self.useMedals.count > 1 && self.displayType == MedalsCenterDisplayType_Square) {
|
||||
// 启动自动轮播,从第一个位置开始
|
||||
[self startAutoScroll:0];
|
||||
|
||||
@@ -722,7 +749,7 @@ typedef enum : NSInteger {
|
||||
self.otherMedal.imageUrl = imageUrl;
|
||||
} else {
|
||||
// 显示默认空勋章图片
|
||||
self.otherMedal.image = kImage(@"medals_empty");
|
||||
self.otherMedal.image = kImage(@"medals_empty_other");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -782,29 +809,34 @@ typedef enum : NSInteger {
|
||||
[self.medalsCollectionView.mj_footer resetNoMoreData];
|
||||
}
|
||||
|
||||
NSMutableArray *itemDataSources = [NSMutableArray array];
|
||||
for (MedalSeriesVo *vo in models) {
|
||||
[itemDataSources addObjectsFromArray:vo.medalSeries];
|
||||
}
|
||||
|
||||
switch (self.currentTabType) {
|
||||
case MedalsCenterTab_TaskMedals:
|
||||
if (self.currentPageTaskMedals == 1) {
|
||||
self.emptyView.hidden = (models.count != 0);
|
||||
self.datasourceTaskMedals = models.mutableCopy;
|
||||
self.datasourceTaskMedals = itemDataSources;
|
||||
} else {
|
||||
[self.datasourceTaskMedals addObjectsFromArray:models];
|
||||
[self.datasourceTaskMedals addObjectsFromArray:itemDataSources];
|
||||
}
|
||||
break;
|
||||
case MedalsCenterTab_ActivityMedals:
|
||||
if (self.currentPageActivityMedals == 1) {
|
||||
self.emptyView.hidden = (models.count != 0);
|
||||
self.datasourceActivityMedals = models.mutableCopy;
|
||||
self.datasourceActivityMedals = itemDataSources;
|
||||
} else {
|
||||
[self.datasourceActivityMedals addObjectsFromArray:models];
|
||||
[self.datasourceActivityMedals addObjectsFromArray:itemDataSources];
|
||||
}
|
||||
break;
|
||||
case MedalsCenterTab_GloryMedals:
|
||||
if (self.currentPageGloryMedals == 1) {
|
||||
self.emptyView.hidden = (models.count != 0);
|
||||
self.datasourceGloryMedals = models.mutableCopy;
|
||||
self.datasourceGloryMedals = itemDataSources;
|
||||
} else {
|
||||
[self.datasourceGloryMedals addObjectsFromArray:models];
|
||||
[self.datasourceGloryMedals addObjectsFromArray:itemDataSources];
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -837,6 +869,7 @@ typedef enum : NSInteger {
|
||||
|
||||
- (void)didTapWearingButton:(UIButton *)sender {
|
||||
MedalsWearingViewController *vc = [[MedalsWearingViewController alloc] init];
|
||||
vc.userInfo = self.userInfo;
|
||||
|
||||
// 设置数据变化回调
|
||||
@kWeakify(self);
|
||||
@@ -852,6 +885,7 @@ typedef enum : NSInteger {
|
||||
|
||||
- (void)didTapEmptyMedalButton:(UIButton *)sender {
|
||||
MedalsWearingViewController *vc = [[MedalsWearingViewController alloc] init];
|
||||
vc.userInfo = self.userInfo;
|
||||
|
||||
// 设置数据变化回调
|
||||
@kWeakify(self);
|
||||
@@ -900,7 +934,7 @@ typedef enum : NSInteger {
|
||||
|
||||
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
MedalsCollectionViewCell *cell = [MedalsCollectionViewCell cellFor:collectionView atIndexPath:indexPath];
|
||||
[cell updateCell:[self loadModel:indexPath.item]];
|
||||
[cell updateCell:[self loadModel:indexPath.item] isForSquare:self.displayType == MedalsCenterDisplayType_Square];
|
||||
return cell;
|
||||
}
|
||||
|
||||
@@ -930,8 +964,8 @@ typedef enum : NSInteger {
|
||||
[self.view addSubview:view];
|
||||
}
|
||||
|
||||
- (MedalSeriesVo *)loadModel:(NSInteger)row {
|
||||
MedalSeriesVo *model = nil;
|
||||
- (MedalSeriesItemVo *)loadModel:(NSInteger)row {
|
||||
MedalSeriesItemVo *model = nil;
|
||||
switch (self.currentTabType) {
|
||||
case MedalsCenterTab_TaskMedals:
|
||||
model = [self.datasourceTaskMedals xpSafeObjectAtIndex:row];
|
||||
@@ -948,6 +982,25 @@ typedef enum : NSInteger {
|
||||
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 {
|
||||
@@ -980,8 +1033,12 @@ typedef enum : NSInteger {
|
||||
[self startAutoScroll:toIndex];
|
||||
}
|
||||
|
||||
MedalVo *vo = [self.useMedals xpSafeObjectAtIndex:toIndex];
|
||||
self.medalDescLabel.text = [vo expireDateString];
|
||||
if (self.displayType == MedalsCenterDisplayType_Mine) {
|
||||
MedalVo *vo = [self.useMedals xpSafeObjectAtIndex:toIndex];
|
||||
self.medalDescLabel.text = [vo expireDateString];
|
||||
} else {
|
||||
self.medalDescLabel.text = @"";
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Lazy load
|
||||
@@ -1115,7 +1172,12 @@ typedef enum : NSInteger {
|
||||
_emptyView = [[UIView alloc] init];
|
||||
_emptyView.backgroundColor = [UIColor clearColor];
|
||||
|
||||
UILabel *titleLabel = [UILabel labelInitWithText:YMLocalizedString(@"20.20.61_text_7")
|
||||
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;
|
||||
|
@@ -186,9 +186,9 @@
|
||||
|
||||
- (void)setMp4Path:(NSString *)mp4Path {
|
||||
// 如果是相同的 mp4 路径,不需要重新加载
|
||||
if ([_mp4Path isEqualToString:mp4Path]) {
|
||||
return;
|
||||
}
|
||||
// if ([_mp4Path isEqualToString:mp4Path]) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// 停止之前的 mp4 播放
|
||||
[self stopMP4Playback];
|
||||
|
@@ -6,13 +6,14 @@
|
||||
//
|
||||
|
||||
#import "MvpViewController.h"
|
||||
|
||||
@class UserInfoModel;
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface MedalsWearingViewController : MvpViewController
|
||||
|
||||
/// 数据变化回调,当佩戴数据发生改变时触发
|
||||
@property (nonatomic, copy) void (^dataChangedCallback)(void);
|
||||
@property (nonatomic, strong) UserInfoModel *userInfo;
|
||||
|
||||
@end
|
||||
|
||||
|
@@ -10,6 +10,8 @@
|
||||
#import "MedalsWearingListCollectionViewCell.h"
|
||||
#import "MedalsWearingControlCollectionViewCell.h"
|
||||
#import "MJRefresh.h"
|
||||
#import "UserInfoModel.h"
|
||||
#import "XPWebViewController.h"
|
||||
|
||||
@interface MedalsWearingViewController () <UICollectionViewDelegateFlowLayout, UICollectionViewDataSource, MedalsPresenterProtocol>
|
||||
|
||||
@@ -221,9 +223,87 @@
|
||||
}
|
||||
|
||||
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
MedalVo *vo = [self.allMedalsVo xpSafeObjectAtIndex:indexPath.row];
|
||||
if (vo) {
|
||||
[self.presenter updateMedalUseStatus:vo.id isUse:!vo.useStatus];
|
||||
if (collectionView == self.controlAreaCollectionView) {
|
||||
// 当前 cell 的座位索引(从1开始)
|
||||
NSInteger currentSeatIndex = indexPath.row + 1;
|
||||
NSString *seatKey = [NSString stringWithFormat:@"%ld", (long)currentSeatIndex];
|
||||
NSArray *vipLevels = self.vipSeatDic[seatKey];
|
||||
|
||||
// 计算当前位置显示的VIP level
|
||||
NSInteger displayedVipLevel = -1;
|
||||
|
||||
// 找到 vipSeatDic 的最小 key
|
||||
NSInteger minSeatIndex = NSIntegerMax;
|
||||
for (NSString *key in self.vipSeatDic.allKeys) {
|
||||
NSInteger seatIndex = [key integerValue];
|
||||
if (seatIndex < minSeatIndex) {
|
||||
minSeatIndex = seatIndex;
|
||||
}
|
||||
}
|
||||
|
||||
// 判断当前位置的VIP level
|
||||
if (minSeatIndex != NSIntegerMax && currentSeatIndex >= minSeatIndex) {
|
||||
if (vipLevels && vipLevels.count > 0) {
|
||||
// 找到最低的 VIP level
|
||||
NSInteger currentMinVipLevel = NSIntegerMax;
|
||||
for (NSNumber *levelNum in vipLevels) {
|
||||
NSInteger level = [levelNum integerValue];
|
||||
if (level < currentMinVipLevel) {
|
||||
currentMinVipLevel = level;
|
||||
}
|
||||
}
|
||||
if (currentMinVipLevel != NSIntegerMax) {
|
||||
displayedVipLevel = currentMinVipLevel;
|
||||
}
|
||||
} else if (self.minVipLevelForSeats > 0) {
|
||||
displayedVipLevel = self.minVipLevelForSeats;
|
||||
}
|
||||
}
|
||||
|
||||
UserVipInfoVo *vipVo = self.userInfo.userVipInfoVO;
|
||||
if (vipVo) {
|
||||
if (vipVo.vipLevel < displayedVipLevel) {
|
||||
TTAlertConfig * config = [[TTAlertConfig alloc] init];
|
||||
// config.actionStyle = 0;
|
||||
config.title = YMLocalizedString(@"20.20.61_text_17");
|
||||
config.message = YMLocalizedString(@"20.20.61_text_15");
|
||||
|
||||
TTAlertButtonConfig *confirmCongif = config.confirmButtonConfig;
|
||||
confirmCongif.title = YMLocalizedString(@"20.20.61_text_18");
|
||||
config.confirmButtonConfig = confirmCongif;
|
||||
@kWeakify(self);
|
||||
[TTPopup alertWithConfig:config confirmHandler:^{
|
||||
@kStrongify(self);
|
||||
XPWebViewController * webVC =[[XPWebViewController alloc] initWithRoomUID:nil];
|
||||
webVC.url = URLWithType(kVIP);
|
||||
[self.navigationController pushViewController:webVC animated:YES];
|
||||
} cancelHandler:^{
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
NSLog(@"[MedalsWearing] 点击位置: %ld, 座位索引: %ld, 显示VIP等级: %ld, VIP数据: %@, 最小座位索引: %ld, 全局最低VIP: %ld",
|
||||
(long)indexPath.row,
|
||||
(long)currentSeatIndex,
|
||||
(long)displayedVipLevel,
|
||||
vipLevels ?: @"无",
|
||||
(long)minSeatIndex,
|
||||
(long)self.minVipLevelForSeats);
|
||||
} else if (collectionView == self.medalsAreaCollectionView) {
|
||||
if (self.useMedalsVo.count >= 10) {
|
||||
TTAlertConfig * config = [[TTAlertConfig alloc] init];
|
||||
config.actionStyle = 0;
|
||||
config.title = YMLocalizedString(@"UserDetail_CP_Toast_0");
|
||||
config.message = YMLocalizedString(@"20.20.61_text_16");
|
||||
[TTPopup alertWithConfig:config confirmHandler:^{
|
||||
} cancelHandler:^{
|
||||
}];
|
||||
} else {
|
||||
MedalVo *vo = [self.allMedalsVo xpSafeObjectAtIndex:indexPath.row];
|
||||
if (vo) {
|
||||
[self.presenter updateMedalUseStatus:vo.id isUse:!vo.useStatus];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -388,7 +388,10 @@ HWDMP4PlayDelegate>
|
||||
|
||||
self.userInfo.relationUserVO = userInfo.relationUserVO;
|
||||
self.headView.relationUser = userInfo.relationUserVO;
|
||||
|
||||
userInfo.medalsPic = self.userInfo.medalsPic;
|
||||
self.headerHeight = [XPMineUserInfoHeaderView headerHeight:userInfo cps:0];
|
||||
|
||||
[self.pagingView reloadData];
|
||||
|
||||
///上传访问记录
|
||||
|
@@ -86,16 +86,14 @@
|
||||
- (void)setRechargeModel:(RechargeListModel *)rechargeModel {
|
||||
_rechargeModel = rechargeModel;
|
||||
NSMutableAttributedString *priceStr = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"$%.2f",rechargeModel.money.floatValue]];
|
||||
// [priceStr addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:8] range:NSMakeRange(0, 1)];
|
||||
self.priceLabel.attributedText = priceStr;
|
||||
NSCharacterSet* nonDigits =[[NSCharacterSet decimalDigitCharacterSet] invertedSet];
|
||||
int remainSecond = [[rechargeModel.prodName stringByTrimmingCharactersInSet:nonDigits] intValue];
|
||||
self.numLabel.text = [NSString stringWithFormat:@"%d",remainSecond];
|
||||
self.numLabel.text = [NSString stringWithFormat:@"%ld",
|
||||
(long)rechargeModel.chargeGoldNum];
|
||||
|
||||
FirstRechargeModel *model = [FirstRechargeManager.sharedManager loadCurrentModel];
|
||||
if (model && model.chargeStatus == NO) {
|
||||
for (FirstRechargeLevelModel *levelModel in model.levelCharge) {
|
||||
if (levelModel.exp == remainSecond) {
|
||||
if (levelModel.exp == rechargeModel.chargeGoldNum) {
|
||||
[self.moneyLabel updateContent: [NSString stringWithFormat:@"+ %@", @(levelModel.awardNum)]];
|
||||
break;
|
||||
}
|
||||
|
@@ -450,32 +450,12 @@ HWDMP4PlayDelegate>
|
||||
self.stack.alignment = UIStackViewAlignmentLeading;
|
||||
self.stack.spacing = 4;
|
||||
|
||||
// if (self.userInfo.guildNameplateIcon.length > 0) {
|
||||
// scrollView.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
// [self.userInfoView addSubview:scrollView];
|
||||
// [scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
// make.leading.mas_equalTo(kGetScaleWidth(15));
|
||||
// make.trailing.mas_equalTo(kGetScaleWidth(-15));
|
||||
// make.top.mas_equalTo(self.nickStackView.mas_bottom).offset(5);
|
||||
// make.height.mas_equalTo(24);
|
||||
// }];
|
||||
// [scrollView addSubview:self.stack];
|
||||
// [self.stack mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
// make.edges.equalTo(scrollView); // 内容视图的边缘与滚动视图一致
|
||||
// make.height.equalTo(scrollView); // 高度与滚动视图一致,确保仅水平滚动
|
||||
// }];
|
||||
//
|
||||
//// if (isMSRTL()) {
|
||||
//// _idEmptyView = [[UIView alloc] init];
|
||||
//// }
|
||||
// } else {
|
||||
[self.userInfoView addSubview:self.stack];
|
||||
[self.stack mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.leading.mas_equalTo(kGetScaleWidth(15));
|
||||
make.top.mas_equalTo(self.nickStackView.mas_bottom).offset(5);
|
||||
make.height.mas_equalTo(24);
|
||||
}];
|
||||
// }
|
||||
[self.userInfoView addSubview:self.stack];
|
||||
[self.stack mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.leading.mas_equalTo(kGetScaleWidth(15));
|
||||
make.top.mas_equalTo(self.nickStackView.mas_bottom).offset(5);
|
||||
make.height.mas_equalTo(24);
|
||||
}];
|
||||
|
||||
[self.stack addArrangedSubview:self.beautIDView];
|
||||
[self.stack addArrangedSubview:self.idLabel];
|
||||
@@ -543,14 +523,21 @@ HWDMP4PlayDelegate>
|
||||
make.top.mas_equalTo(self.nameplateCollectionView.mas_bottom).offset(6);
|
||||
make.leading.mas_equalTo(self.userInfoView).offset(kGetScaleWidth(15));
|
||||
make.trailing.mas_equalTo(self.userInfoView).offset(kGetScaleWidth(-15));
|
||||
make.height.mas_equalTo(kGetScaleWidth(30));
|
||||
make.height.mas_equalTo(0);
|
||||
}];
|
||||
|
||||
UIView *container = [[UIView alloc] init];
|
||||
container.backgroundColor = [UIColor clearColor];
|
||||
[self.medalsScrollView addSubview:container];
|
||||
[container mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.edges.mas_equalTo(self.medalsScrollView);
|
||||
}];
|
||||
|
||||
// 在 ScrollView 中添加 StackView
|
||||
[self.medalsScrollView addSubview:self.medalsStackView];
|
||||
[container addSubview:self.medalsStackView];
|
||||
[self.medalsStackView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.edges.mas_equalTo(self.medalsScrollView);
|
||||
make.height.mas_equalTo(self.medalsScrollView);
|
||||
make.edges.mas_equalTo(container);
|
||||
make.height.mas_equalTo(kGetScaleWidth(30));
|
||||
}];
|
||||
|
||||
// 默认隐藏,有数据时再显示
|
||||
@@ -1648,8 +1635,8 @@ HWDMP4PlayDelegate>
|
||||
_medalsStackView = [[UIStackView alloc] init];
|
||||
_medalsStackView.backgroundColor = [UIColor clearColor];
|
||||
_medalsStackView.axis = UILayoutConstraintAxisHorizontal;
|
||||
_medalsStackView.distribution = UIStackViewDistributionEqualSpacing;
|
||||
_medalsStackView.alignment = UIStackViewAlignmentCenter;
|
||||
_medalsStackView.distribution = UIStackViewDistributionFill;//UIStackViewDistributionEqualSpacing;
|
||||
_medalsStackView.alignment = UIStackViewAlignmentLeading;
|
||||
_medalsStackView.spacing = 5;
|
||||
}
|
||||
return _medalsStackView;
|
||||
@@ -1679,6 +1666,10 @@ HWDMP4PlayDelegate>
|
||||
return;
|
||||
}
|
||||
|
||||
[self.medalsScrollView mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||
make.height.mas_equalTo(kGetScaleWidth(30));
|
||||
}];
|
||||
|
||||
self.medalsScrollView.hidden = NO;
|
||||
NSMutableArray<VAPView *> *mp4Views = [NSMutableArray array];
|
||||
|
||||
@@ -1731,17 +1722,17 @@ HWDMP4PlayDelegate>
|
||||
[self.medalsStackView addArrangedSubview:medalContainer];
|
||||
[medalContainer mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.width.height
|
||||
.mas_equalTo(kGetScaleWidth(30))
|
||||
.priority(UILayoutPriorityRequired);
|
||||
.mas_equalTo(kGetScaleWidth(30));
|
||||
// .priority(UILayoutPriorityRequired);
|
||||
}];
|
||||
|
||||
// 设置内容压缩阻力优先级,防止被压缩
|
||||
[medalContainer setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
|
||||
[medalContainer setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
|
||||
|
||||
// 设置内容拥抱优先级,防止被拉伸
|
||||
[medalContainer setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
|
||||
[medalContainer setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
|
||||
// // 设置内容压缩阻力优先级,防止被压缩
|
||||
// [medalContainer setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
|
||||
// [medalContainer setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
|
||||
//
|
||||
// // 设置内容拥抱优先级,防止被拉伸
|
||||
// [medalContainer setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
|
||||
// [medalContainer setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
|
||||
}
|
||||
|
||||
// 更新 ScrollView 的 contentSize
|
||||
@@ -1752,6 +1743,19 @@ HWDMP4PlayDelegate>
|
||||
CGFloat expectedWidth = count * kGetScaleWidth(30) + (count - 1) * 5;
|
||||
stackViewWidth = expectedWidth;
|
||||
}
|
||||
|
||||
CGFloat targetWidth = KScreenWidth - kGetScaleWidth(40);
|
||||
if (stackViewWidth < targetWidth) {
|
||||
UIView *v = [[UIView alloc] initWithFrame:CGRectMake(0, 0, targetWidth, kGetScaleWidth(30))];
|
||||
v.backgroundColor = [UIColor clearColor];
|
||||
[self.medalsStackView addArrangedSubview:v];
|
||||
[v mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.size
|
||||
.mas_equalTo(CGSizeMake(targetWidth-stackViewWidth, kGetScaleWidth(30)));
|
||||
}];
|
||||
stackViewWidth = targetWidth;
|
||||
}
|
||||
[self.medalsStackView layoutIfNeeded];
|
||||
self.medalsScrollView.contentSize = CGSizeMake(stackViewWidth, kGetScaleWidth(30));
|
||||
|
||||
self.medalMP4Views = [mp4Views copy];
|
||||
|
@@ -518,11 +518,11 @@ UIKIT_EXTERN NSString *kRequestTicket;
|
||||
}
|
||||
///转赠钻石
|
||||
-(void)pushGiveDiamondVC{
|
||||
// XPWebViewController * webVC =[[XPWebViewController alloc] initWithRoomUID:nil];
|
||||
// webVC.url = URLWithType(kTransfer);
|
||||
// [self.navigationController pushViewController:webVC animated:YES];
|
||||
XPMineGiveDiamondVC *giveDiamondVC = [[XPMineGiveDiamondVC alloc] initWithUserModel:self.userInfo];
|
||||
[self.navigationController pushViewController:giveDiamondVC animated:YES];
|
||||
XPWebViewController * webVC =[[XPWebViewController alloc] initWithRoomUID:nil];
|
||||
webVC.url = URLWithType(kTransfer);
|
||||
[self.navigationController pushViewController:webVC animated:YES];
|
||||
// XPMineGiveDiamondVC *giveDiamondVC = [[XPMineGiveDiamondVC alloc] initWithUserModel:self.userInfo];
|
||||
// [self.navigationController pushViewController:giveDiamondVC animated:YES];
|
||||
}
|
||||
///点击充值
|
||||
-(void)pushThirdPartyPayVC{
|
||||
|
@@ -10,11 +10,16 @@
|
||||
#import "XPNewHomeViewController.h"
|
||||
#import "XPHomeMineViewController.h"
|
||||
#import "XPRoomSearchContainerViewController.h"
|
||||
#import "XPWebViewController.h"
|
||||
|
||||
#import "Api+Gift.h"
|
||||
#import "XPGiftStorage.h"
|
||||
#import "FirstRechargeManager.h"
|
||||
#import "FirstRechargeModel.h"
|
||||
#import "YUMIHtmlUrl.h"
|
||||
#import "YUMIMacroUitls.h"
|
||||
|
||||
@interface XPHomePagingViewController () <UIPageViewControllerDelegate, UIPageViewControllerDataSource>
|
||||
@interface XPHomePagingViewController () <UIPageViewControllerDelegate, UIPageViewControllerDataSource, FirstRechargeManagerDelegate>
|
||||
|
||||
@property (nonatomic, strong) UIView *topControlView;
|
||||
@property (nonatomic, strong) UIButton *mineButton;
|
||||
@@ -27,10 +32,20 @@
|
||||
@property (nonatomic, strong) XPNewHomeViewController *recommendVC;
|
||||
@property (nonatomic, strong) XPHomeMineViewController *mineVC;
|
||||
|
||||
// 首充弹窗引用
|
||||
@property (nonatomic, strong) XPWebViewController *firstChargeWebVC;
|
||||
// 首充弹窗背景视图
|
||||
@property (nonatomic, strong) UIView *firstChargeBackgroundView;
|
||||
|
||||
@end
|
||||
|
||||
@implementation XPHomePagingViewController
|
||||
|
||||
- (void)dealloc {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
[FirstRechargeManager sharedManager].delegate = nil;
|
||||
}
|
||||
|
||||
- (BOOL)isHiddenNavBar {
|
||||
return YES;
|
||||
}
|
||||
@@ -38,6 +53,18 @@
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
[self setup];
|
||||
|
||||
// 注册首充管理器监听
|
||||
[FirstRechargeManager sharedManager].delegate = self;
|
||||
}
|
||||
|
||||
- (void)viewDidAppear:(BOOL)animated {
|
||||
[super viewDidAppear:animated];
|
||||
|
||||
// 启动首充监控
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(4 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
[[FirstRechargeManager sharedManager] startMonitoring];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)setup {
|
||||
@@ -193,4 +220,113 @@
|
||||
[self displayRecommendTab];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)tokenInvalid {
|
||||
// 停止首充监控
|
||||
[[FirstRechargeManager sharedManager] stopMonitoring];
|
||||
|
||||
// [super tokenInvalid];
|
||||
}
|
||||
|
||||
#pragma mark - FirstRechargeManagerDelegate
|
||||
|
||||
- (void)firstRechargeManager:(FirstRechargeManager *)manager didCheckFirstRecharge:(FirstRechargeModel *)model shouldShow:(BOOL)shouldShow {
|
||||
if (shouldShow && model.chargeStatus == NO) {
|
||||
// 展示首充弹窗
|
||||
[self showFirstRechargePopup:model];
|
||||
|
||||
// 标记今天已展示过(在展示后标记)
|
||||
[[FirstRechargeManager sharedManager] markTodayShown];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)showFirstRechargePopup:(FirstRechargeModel *)model {
|
||||
if (model.chargeStatus) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果已经有弹窗在显示,先移除它
|
||||
[self removeFirstChargePopup];
|
||||
|
||||
// 创建背景视图
|
||||
self.firstChargeBackgroundView = [[UIView alloc] initWithFrame:self.view.bounds];
|
||||
self.firstChargeBackgroundView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.5];
|
||||
self.firstChargeBackgroundView.alpha = 0;
|
||||
|
||||
// 添加点击手势
|
||||
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleBackgroundTap:)];
|
||||
[self.firstChargeBackgroundView addGestureRecognizer:tapGesture];
|
||||
|
||||
// 添加到当前视图
|
||||
[self.view addSubview:self.firstChargeBackgroundView];
|
||||
|
||||
// 创建并配置 web 视图
|
||||
self.firstChargeWebVC = [[XPWebViewController alloc] initWithRoomUID:@""];
|
||||
self.firstChargeWebVC.isPush = NO;
|
||||
self.firstChargeWebVC.url = URLWithType(kFirstChargeHomeIndex);
|
||||
|
||||
[self addChildViewController:self.firstChargeWebVC];
|
||||
[self.firstChargeBackgroundView addSubview:self.firstChargeWebVC.view];
|
||||
[self.firstChargeWebVC didMoveToParentViewController:self];
|
||||
|
||||
self.firstChargeWebVC.view.backgroundColor = [UIColor clearColor];
|
||||
self.firstChargeWebVC.webview.backgroundColor = [UIColor clearColor];
|
||||
self.firstChargeWebVC.webview.opaque = NO;
|
||||
self.firstChargeWebVC.webview.scrollView.backgroundColor = [UIColor clearColor];
|
||||
self.firstChargeWebVC.view.frame = CGRectMake(0,
|
||||
0,
|
||||
kGetScaleWidth(305),
|
||||
kGetScaleWidth(403));
|
||||
self.firstChargeWebVC.view.center = self.firstChargeBackgroundView.center;
|
||||
|
||||
@kWeakify(self);
|
||||
[self.firstChargeWebVC setUrlLoadCompleted:^(BOOL result, NSError * _Nullable error) {
|
||||
@kStrongify(self);
|
||||
[UIView animateWithDuration:0.5 animations:^{
|
||||
self.firstChargeBackgroundView.alpha = 1;
|
||||
}];
|
||||
}];
|
||||
[self.firstChargeWebVC setDidTapCharge:^{
|
||||
@kStrongify(self);
|
||||
[self removeFirstChargePopup];
|
||||
}];
|
||||
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(4 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
[self removeFirstChargePopup];
|
||||
});
|
||||
}
|
||||
|
||||
// 处理背景点击事件
|
||||
- (void)handleBackgroundTap:(UITapGestureRecognizer *)gesture {
|
||||
// 获取点击位置
|
||||
CGPoint location = [gesture locationInView:self.firstChargeBackgroundView];
|
||||
|
||||
// 检查是否点击在 webView 区域外
|
||||
if (self.firstChargeWebVC && self.firstChargeWebVC.view) {
|
||||
CGRect webViewFrame = self.firstChargeWebVC.view.frame;
|
||||
if (!CGRectContainsPoint(webViewFrame, location)) {
|
||||
// 点击在 webView 外部,移除弹窗
|
||||
[self removeFirstChargePopup];
|
||||
}
|
||||
} else {
|
||||
// 如果 webView 不存在,直接移除弹窗
|
||||
[self removeFirstChargePopup];
|
||||
}
|
||||
}
|
||||
|
||||
// 移除弹窗
|
||||
- (void)removeFirstChargePopup {
|
||||
if (self.firstChargeWebVC) {
|
||||
[self.firstChargeWebVC willMoveToParentViewController:nil];
|
||||
[self.firstChargeWebVC.view removeFromSuperview];
|
||||
[self.firstChargeWebVC removeFromParentViewController];
|
||||
self.firstChargeWebVC = nil;
|
||||
}
|
||||
|
||||
if (self.firstChargeBackgroundView) {
|
||||
[self.firstChargeBackgroundView removeFromSuperview];
|
||||
self.firstChargeBackgroundView = nil;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
@@ -13,7 +13,6 @@
|
||||
#import <JXCategoryView/JXCategoryView.h>
|
||||
#import <MJRefresh/MJRefresh.h>
|
||||
#import "SDWebImageManager.h"
|
||||
#import "FirstRechargeManager.h"
|
||||
///Tool
|
||||
#import "Api+Home.h"
|
||||
#import "YUMIMacroUitls.h"
|
||||
@@ -330,8 +329,7 @@ JXCategoryViewDelegate,
|
||||
XPHomeContainerProtocol,
|
||||
XPNewHomeNavViewDelegate,
|
||||
XPNewHomeHeadViewDelegate,
|
||||
XPHomeRecommendOtherRoomViewDelegate,
|
||||
FirstRechargeManagerDelegate>
|
||||
XPHomeRecommendOtherRoomViewDelegate>
|
||||
|
||||
///头视图
|
||||
@property(nonatomic,strong) XPNewHomeHeadView *headView;
|
||||
@@ -359,11 +357,6 @@ FirstRechargeManagerDelegate>
|
||||
|
||||
@property (nonatomic, assign) bool hasLoadAPIs;
|
||||
|
||||
// 首充弹窗引用
|
||||
@property (nonatomic, strong) XPWebViewController *firstChargeWebVC;
|
||||
// 首充弹窗背景视图
|
||||
@property (nonatomic, strong) UIView *firstChargeBackgroundView;
|
||||
|
||||
@end
|
||||
|
||||
@implementation XPNewHomeViewController
|
||||
@@ -377,7 +370,6 @@ FirstRechargeManagerDelegate>
|
||||
|
||||
-(void)dealloc{
|
||||
[[NSNotificationCenter defaultCenter]removeObserver:self];
|
||||
[FirstRechargeManager sharedManager].delegate = nil;
|
||||
}
|
||||
|
||||
- (BOOL)isHiddenNavBar {
|
||||
@@ -398,12 +390,6 @@ FirstRechargeManagerDelegate>
|
||||
[self initSubViewConstraints];
|
||||
|
||||
[self requestCheckIp];
|
||||
|
||||
// 注册首充管理器监听
|
||||
[FirstRechargeManager sharedManager].delegate = self;
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(4 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
[[FirstRechargeManager sharedManager] startMonitoring];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -416,13 +402,10 @@ FirstRechargeManagerDelegate>
|
||||
});
|
||||
self.hasLoadAPIs = YES;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
- (void)tokenInvalid {
|
||||
// 停止首充监控
|
||||
[[FirstRechargeManager sharedManager] stopMonitoring];
|
||||
|
||||
[[AccountInfoStorage instance] saveAccountInfo:nil];
|
||||
[[AccountInfoStorage instance] saveTicket:nil];
|
||||
if ([NIMSDK sharedSDK].loginManager.isLogined) {
|
||||
@@ -786,135 +769,7 @@ FirstRechargeManagerDelegate>
|
||||
self.type = index;
|
||||
}
|
||||
|
||||
- (void)getFirstChargeSuccess:(FirstRechargeModel *)model {
|
||||
if (model.chargeStatus == NO) {
|
||||
// TODO: 弹出窗口 web view
|
||||
XPWebViewController *web = [[XPWebViewController alloc] initWithRoomUID:@""];
|
||||
[self addChildViewController:web];
|
||||
[self.view addSubview:web.view];
|
||||
web.view.frame = CGRectMake(0, 0, KScreenWidth/2, KScreenHeight/2);
|
||||
web.view.center = self.view.center;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - FirstRechargeManagerDelegate
|
||||
|
||||
- (void)firstRechargeManager:(FirstRechargeManager *)manager didCheckFirstRecharge:(FirstRechargeModel *)model shouldShow:(BOOL)shouldShow {
|
||||
if (shouldShow && model.chargeStatus == NO) {
|
||||
// 展示首充弹窗
|
||||
[self showFirstRechargePopup:model];
|
||||
|
||||
// 标记今天已展示过(在展示后标记)
|
||||
[[FirstRechargeManager sharedManager] markTodayShown];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)showFirstRechargePopup:(FirstRechargeModel *)model {
|
||||
if (model.chargeStatus) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果已经有弹窗在显示,先移除它
|
||||
[self removeFirstChargePopup];
|
||||
|
||||
// 获取 keyWindow 以确保盖在 tabbar 上
|
||||
UIWindow *keyWindow = [UIApplication sharedApplication].keyWindow;
|
||||
if (!keyWindow) {
|
||||
keyWindow = [UIApplication sharedApplication].windows.firstObject;
|
||||
}
|
||||
|
||||
// 创建背景视图,使用 keyWindow 的 bounds
|
||||
self.firstChargeBackgroundView = [[UIView alloc] initWithFrame:keyWindow.bounds];
|
||||
self.firstChargeBackgroundView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.5];
|
||||
|
||||
// 添加点击手势
|
||||
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleBackgroundTap:)];
|
||||
[self.firstChargeBackgroundView addGestureRecognizer:tapGesture];
|
||||
|
||||
// 添加到 keyWindow 上,确保盖在 tabbar 上
|
||||
[keyWindow addSubview:self.firstChargeBackgroundView];
|
||||
|
||||
// 创建并配置 web 视图
|
||||
self.firstChargeWebVC = [[XPWebViewController alloc] initWithRoomUID:@""];
|
||||
self.firstChargeWebVC.isPush = NO;
|
||||
self.firstChargeWebVC.url = URLWithType(kFirstChargeHomeIndex);
|
||||
|
||||
// 获取当前的根视图控制器来添加子控制器
|
||||
UIViewController *rootViewController = keyWindow.rootViewController;
|
||||
if ([rootViewController isKindOfClass:[UINavigationController class]]) {
|
||||
rootViewController = [(UINavigationController *)rootViewController topViewController];
|
||||
} else if ([rootViewController isKindOfClass:[UITabBarController class]]) {
|
||||
UITabBarController *tabBarController = (UITabBarController *)rootViewController;
|
||||
rootViewController = tabBarController.selectedViewController;
|
||||
if ([rootViewController isKindOfClass:[UINavigationController class]]) {
|
||||
rootViewController = [(UINavigationController *)rootViewController topViewController];
|
||||
}
|
||||
}
|
||||
|
||||
[rootViewController addChildViewController:self.firstChargeWebVC];
|
||||
[self.firstChargeBackgroundView addSubview:self.firstChargeWebVC.view];
|
||||
[self.firstChargeWebVC didMoveToParentViewController:rootViewController];
|
||||
|
||||
self.firstChargeWebVC.view.backgroundColor = [UIColor clearColor];
|
||||
self.firstChargeWebVC.webview.backgroundColor = [UIColor clearColor];
|
||||
self.firstChargeWebVC.webview.opaque = NO;
|
||||
self.firstChargeWebVC.webview.scrollView.backgroundColor = [UIColor clearColor];
|
||||
self.firstChargeWebVC.view.frame = CGRectMake(0, 0, KScreenWidth - 40, KScreenHeight*2/3);
|
||||
self.firstChargeWebVC.view.center = self.firstChargeBackgroundView.center;
|
||||
|
||||
// 添加关闭按钮
|
||||
// UIButton *closeButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
// [closeButton setTitle:@"✕" forState:UIControlStateNormal];
|
||||
// [closeButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
|
||||
// closeButton.titleLabel.font = [UIFont systemFontOfSize:16 weight:UIFontWeightBold];
|
||||
// [closeButton addTarget:self action:@selector(removeFirstChargePopup) forControlEvents:UIControlEventTouchUpInside];
|
||||
// closeButton.frame = CGRectMake(0, 0, 30, 30);
|
||||
// closeButton.backgroundColor = [UIColor colorWithWhite:0 alpha:0.5];
|
||||
// closeButton.layer.cornerRadius = 15;
|
||||
// [self.firstChargeBackgroundView addSubview:closeButton];
|
||||
//
|
||||
// // 设置关闭按钮位置(webView 右上角)
|
||||
// CGRect webViewFrame = self.firstChargeWebVC.view.frame;
|
||||
// closeButton.center = CGPointMake(CGRectGetMaxX(webViewFrame) - 15, CGRectGetMinY(webViewFrame) + 15);
|
||||
|
||||
// 3秒后自动移除
|
||||
// dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(4.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
// [self removeFirstChargePopup];
|
||||
// });
|
||||
}
|
||||
|
||||
// 处理背景点击事件
|
||||
- (void)handleBackgroundTap:(UITapGestureRecognizer *)gesture {
|
||||
// 获取点击位置
|
||||
CGPoint location = [gesture locationInView:self.firstChargeBackgroundView];
|
||||
|
||||
// 检查是否点击在 webView 区域外
|
||||
if (self.firstChargeWebVC && self.firstChargeWebVC.view) {
|
||||
CGRect webViewFrame = self.firstChargeWebVC.view.frame;
|
||||
if (!CGRectContainsPoint(webViewFrame, location)) {
|
||||
// 点击在 webView 外部,移除弹窗
|
||||
[self removeFirstChargePopup];
|
||||
}
|
||||
} else {
|
||||
// 如果 webView 不存在,直接移除弹窗
|
||||
[self removeFirstChargePopup];
|
||||
}
|
||||
}
|
||||
|
||||
// 修改移除弹窗的方法
|
||||
- (void)removeFirstChargePopup {
|
||||
if (self.firstChargeWebVC) {
|
||||
[self.firstChargeWebVC willMoveToParentViewController:nil];
|
||||
[self.firstChargeWebVC.view removeFromSuperview];
|
||||
[self.firstChargeWebVC removeFromParentViewController];
|
||||
self.firstChargeWebVC = nil;
|
||||
}
|
||||
|
||||
if (self.firstChargeBackgroundView) {
|
||||
[self.firstChargeBackgroundView removeFromSuperview];
|
||||
self.firstChargeBackgroundView = nil;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - XPNewHomeHeadViewDelegate
|
||||
///
|
||||
|
@@ -106,9 +106,7 @@
|
||||
[[NIMSDK sharedSDK].chatroomManager enterChatroom:request completion:^(NSError * _Nullable error, NIMChatroom * _Nullable chatroom, NIMChatroomMember * _Nullable me) {
|
||||
@kStrongify(self);
|
||||
if (error) {
|
||||
#ifdef DEBUG
|
||||
NSLog(@"\n云信进房异常:\n %@", error);
|
||||
#endif
|
||||
NSLog(@"\n云信进房异常:\n %@", error);
|
||||
[[self getView] enterRoomFail:error.code];
|
||||
} else {
|
||||
[[self getView] enterRoomSuccess:chatroom];
|
||||
|
@@ -36,6 +36,11 @@
|
||||
CGSize size = [content boundingRectWithSize:CGSizeMake(width, 0)
|
||||
options:NSStringDrawingUsesFontLeading | NSStringDrawingUsesLineFragmentOrigin
|
||||
context:nil].size;
|
||||
|
||||
if (self.first == 9 && self.second == 91) {
|
||||
self.rowHeight = 100;
|
||||
return;
|
||||
}
|
||||
|
||||
YYTextContainer *container = [YYTextContainer containerWithSize:CGSizeMake(size.width, CGFLOAT_MAX)];
|
||||
container.maximumNumberOfRows = 0;
|
||||
@@ -45,6 +50,7 @@
|
||||
|
||||
CGSize textSize = textLayout.textBoundingRect.size;
|
||||
self.textWidth = textSize.width;
|
||||
|
||||
if ([NSString isEmpty:self.bubbleImageUrl]) {
|
||||
self.rowHeight =
|
||||
ceil(textSize.height) +
|
||||
@@ -61,5 +67,19 @@
|
||||
self.rowHeight += 10;
|
||||
// }
|
||||
self.rowHeight += (self.isBoom ? 20 : 0);
|
||||
if ([self isStringContainArabic:content.string]) {
|
||||
self.rowHeight += 20;
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)isStringContainArabic:(NSString *)string {
|
||||
for (NSUInteger i = 0; i < string.length; i++) {
|
||||
unichar c = [string characterAtIndex:i];
|
||||
if (c >= 0x0600 && c <= 0x06FF) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
|
@@ -1012,6 +1012,9 @@
|
||||
- (XPMessageInfoModel*)createRoomFaceAttribute:(AttachmentModel *)attachment
|
||||
messageInfo:(XPMessageInfoModel *)messageInfo
|
||||
remoteExtModel:(XPMessageRemoteExtModel *)model {
|
||||
messageInfo.first = attachment.first;
|
||||
messageInfo.second = attachment.second;
|
||||
|
||||
NSMutableAttributedString * attribute = [[NSMutableAttributedString alloc] init];
|
||||
///官方新用户
|
||||
[attribute appendAttributedString:[self createOfficalAndNewuserAttribute:model.defUser newUser:model.newUser fromSayHelloChannel:model.fromSayHelloChannel]];
|
||||
@@ -1094,7 +1097,6 @@
|
||||
}
|
||||
}
|
||||
messageInfo.content = attribute;
|
||||
messageInfo.first = attachment.first;
|
||||
return messageInfo;
|
||||
}
|
||||
|
||||
|
@@ -141,7 +141,7 @@
|
||||
FirstRechargeModel *model = [[FirstRechargeManager sharedManager] loadCurrentModel];
|
||||
if (model && model.chargeStatus == NO) {
|
||||
self.firstChargeView.hidden = NO;
|
||||
[self.moneyLabel updateContent:@"Bonus >"];
|
||||
[self.moneyLabel updateContent:YMLocalizedString(@"20.20.61_text_19")];
|
||||
} else {
|
||||
self.firstChargeView.hidden = YES;
|
||||
}
|
||||
@@ -164,9 +164,18 @@
|
||||
}];
|
||||
|
||||
[self.firstChargeView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.size.mas_equalTo(CGSizeMake(68, 23));
|
||||
make.height.mas_equalTo(23);
|
||||
make.leading.mas_equalTo(self.rechargeStackView.mas_leading);
|
||||
make.centerY.mas_equalTo(self.rechargeStackView);
|
||||
if (isMSZH()) {
|
||||
make.width.mas_equalTo(80);
|
||||
} else if (isMSRTL()) {
|
||||
make.width.mas_equalTo(76);
|
||||
} else if (isMSTR()) {
|
||||
make.width.mas_equalTo(70);
|
||||
} else {
|
||||
make.width.mas_equalTo(70);
|
||||
}
|
||||
}];
|
||||
|
||||
[self.sendOperationView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
@@ -546,7 +555,19 @@
|
||||
|
||||
[_firstChargeView addSubview:self.moneyLabel];
|
||||
[self.moneyLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.edges.mas_equalTo(_firstChargeView).insets(UIEdgeInsetsMake(5, 5, 5, 5));
|
||||
make.edges.mas_equalTo(_firstChargeView).insets(UIEdgeInsetsMake(5, 5, 5, 10));
|
||||
}];
|
||||
|
||||
UIImageView *arrow = [[UIImageView alloc] initWithImage:[kImage(@"brown_arrow") ms_SetImageForRTL]];
|
||||
[_firstChargeView addSubview:arrow];
|
||||
[arrow mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.centerY.mas_equalTo(_firstChargeView);
|
||||
if (isMSRTL()) {
|
||||
make.leading.mas_equalTo(self.moneyLabel.mas_trailing).offset(-10);
|
||||
}else {
|
||||
make.leading.mas_equalTo(self.moneyLabel.mas_trailing).offset(-5);
|
||||
}
|
||||
make.size.mas_equalTo(CGSizeMake(12, 12));
|
||||
}];
|
||||
|
||||
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didTagRecharge:)];
|
||||
@@ -557,7 +578,7 @@
|
||||
|
||||
- (MoliMoneyLabel *)moneyLabel {
|
||||
if (!_moneyLabel) {
|
||||
_moneyLabel = [MoliMoneyLabel moneyLabelWithTextColot:UIColorFromRGB(0x582B00) font:kFontSemibold(10) moneyPostion:1 moneySize:CGSizeMake(15, 15)];
|
||||
_moneyLabel = [MoliMoneyLabel moneyLabelWithTextColot:UIColorFromRGB(0x582B00) font:kFontSemibold(12) moneyPostion:1 moneySize:CGSizeMake(15, 15)];
|
||||
}
|
||||
return _moneyLabel;
|
||||
}
|
||||
|
@@ -461,7 +461,7 @@
|
||||
|
||||
[self.medalsScrollView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.centerX.mas_equalTo(self.contentView);
|
||||
make.centerY.mas_equalTo(self.contentView);
|
||||
make.top.mas_equalTo(self.contentView);
|
||||
make.height.mas_equalTo(kGetScaleWidth(30));
|
||||
// 初始设置一个默认宽度,后续会动态更新
|
||||
self.scrollViewWidthConstraint = make.width.mas_equalTo(maxMedalsWidth);
|
||||
|
@@ -43,6 +43,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@property(nonatomic, copy) void (^verifyCaptcha)(BOOL result);
|
||||
|
||||
@property (nonatomic, copy) void(^didTapCharge)(void);
|
||||
|
||||
- (instancetype)initWithCustomizeNav:(BOOL)isCustom;
|
||||
|
||||
///强制使用 roomUID 初始化,尽量传入,防止 web 在需要时取不到数据
|
||||
|
@@ -373,9 +373,10 @@ NSString * const kJSShowShareCallBack = @"showShareAction";
|
||||
NSString *currentUrl = [NSString stringWithFormat:@"%@", response];
|
||||
///测试环境只要有host就执行,方便h5连接本地调试
|
||||
BOOL condition = currentUrl != nil && [currentUrl containsString:API_HOST_URL];
|
||||
#ifdef DEBUG
|
||||
|
||||
NSLog(@"-- -- - -- - - | -- -- - -- - -%@", response);
|
||||
NSLog(@"-- -- - -- - -%@: %@", message.name, message.body);
|
||||
#ifdef DEBUG
|
||||
condition = currentUrl != nil;
|
||||
#endif
|
||||
if(condition) {
|
||||
@@ -450,6 +451,11 @@ NSString * const kJSShowShareCallBack = @"showShareAction";
|
||||
webVC.type = @"4";
|
||||
[[XCCurrentVCStackManager shareManager].getCurrentVC.navigationController pushViewController:webVC animated:YES];
|
||||
}
|
||||
|
||||
if (self.didTapCharge) {
|
||||
self.didTapCharge();
|
||||
}
|
||||
|
||||
} else if ([message.name isEqualToString:kOpenPersonPage]) {
|
||||
NSString *uid = [NSString stringWithFormat:@"%@",message.body];
|
||||
if (uid.integerValue > 0) {
|
||||
|
@@ -71,6 +71,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
*/
|
||||
@property (nonatomic, assign) NSInteger busType;
|
||||
|
||||
@property (nonatomic,copy) NSString *mp4Url;
|
||||
|
||||
@end
|
||||
|
||||
@interface MedalModel : PIBaseModel
|
||||
|
@@ -125,12 +125,18 @@
|
||||
- (void)accountCanceled:(NSDictionary *)data {
|
||||
NSString *date = [NSString stringWithFormat:@"%.0f",[[data objectForKey:@"cancelDate"] doubleValue]];
|
||||
NSString *dateDes = [NSString stringWithFormat:YMLocalizedString(@"MvpViewController0"), [PLTimeUtil getDateWithYYMMDD:date]];
|
||||
NSString *msg = [NSString stringWithFormat:YMLocalizedString(@"MvpViewController1"), dateDes];
|
||||
NSString *msg = [NSString stringWithFormat:YMLocalizedString(@"MvpViewController1.1"), dateDes];
|
||||
if ([[data objectForKey:@"cancelDate"] doubleValue] == 0) {
|
||||
dateDes = @"";
|
||||
msg = YMLocalizedString(@"MvpViewController1.2");
|
||||
}
|
||||
|
||||
TTAlertMessageAttributedConfig *dateAttrConfig = [[TTAlertMessageAttributedConfig alloc] init];
|
||||
dateAttrConfig.text = dateDes;
|
||||
dateAttrConfig.color = DJDKMIMOMColor.appMainColor;
|
||||
|
||||
TTAlertConfig *config = [[TTAlertConfig alloc] init];
|
||||
config.actionStyle = 0;
|
||||
config.title = YMLocalizedString(@"MvpViewController2");
|
||||
config.message = msg;
|
||||
config.messageAttributedConfig = @[dateAttrConfig];
|
||||
|
@@ -15,14 +15,14 @@
|
||||
static NSString * const kFirstRechargeModelKey = @"FirstRechargeModel";
|
||||
static NSString * const kLastCheckDateKey = @"FirstRechargeLastCheckDate";
|
||||
static NSString * const kTodayShownKey = @"FirstRechargeTodayShown";
|
||||
|
||||
|
||||
static NSString * const kCurrentUserIdKey = @"FirstRechargeCurrentUserId";
|
||||
|
||||
@interface FirstRechargeManager ()
|
||||
|
||||
@property (nonatomic, strong) FirstRechargeModel *currentFirstRechargeData;
|
||||
@property (nonatomic, strong) NSTimer *dailyTimer;
|
||||
@property (nonatomic, assign) BOOL isMonitoring;
|
||||
@property (nonatomic, copy) NSString *currentUserId;
|
||||
|
||||
@end
|
||||
|
||||
@@ -42,6 +42,7 @@ static NSString * const kTodayShownKey = @"FirstRechargeTodayShown";
|
||||
if (self) {
|
||||
_isMonitoring = NO;
|
||||
[self loadCachedModel];
|
||||
[self updateCurrentUserId];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@@ -63,6 +64,9 @@ static NSString * const kTodayShownKey = @"FirstRechargeTodayShown";
|
||||
|
||||
self.isMonitoring = YES;
|
||||
|
||||
// 检查用户是否切换
|
||||
[self checkUserSwitch];
|
||||
|
||||
// 立即检查一次
|
||||
[self checkFirstRechargeStatus];
|
||||
|
||||
@@ -99,8 +103,7 @@ static NSString * const kTodayShownKey = @"FirstRechargeTodayShown";
|
||||
|
||||
- (void)markTodayShown {
|
||||
NSString *today = [self getTodayString];
|
||||
[[NSUserDefaults standardUserDefaults] setObject:today forKey:kTodayShownKey];
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
[self setTodayShownForCurrentUser:today];
|
||||
}
|
||||
|
||||
#pragma mark - Private Methods
|
||||
@@ -140,6 +143,9 @@ static NSString * const kTodayShownKey = @"FirstRechargeTodayShown";
|
||||
}
|
||||
|
||||
- (void)applicationDidBecomeActive {
|
||||
// 检查用户是否切换
|
||||
[self checkUserSwitch];
|
||||
|
||||
// 应用进入前台时检查是否需要更新
|
||||
if ([self shouldCheckToday]) {
|
||||
[self checkFirstRechargeStatus];
|
||||
@@ -147,7 +153,8 @@ static NSString * const kTodayShownKey = @"FirstRechargeTodayShown";
|
||||
}
|
||||
|
||||
- (BOOL)shouldCheckToday {
|
||||
NSString *lastCheckDate = [[NSUserDefaults standardUserDefaults] objectForKey:kLastCheckDateKey];
|
||||
NSString *userSpecificKey = [self getUserSpecificKey:kLastCheckDateKey];
|
||||
NSString *lastCheckDate = [[NSUserDefaults standardUserDefaults] objectForKey:userSpecificKey];
|
||||
NSString *today = [self getTodayString];
|
||||
|
||||
return ![today isEqualToString:lastCheckDate];
|
||||
@@ -160,6 +167,9 @@ static NSString * const kTodayShownKey = @"FirstRechargeTodayShown";
|
||||
return;
|
||||
}
|
||||
|
||||
// 更新当前用户ID
|
||||
[self updateCurrentUserId];
|
||||
|
||||
// 调用API获取首充信息
|
||||
@kWeakify(self);
|
||||
[Api firstchargeInfo:^(BaseModel * _Nullable data, NSInteger code, NSString * _Nullable msg) {
|
||||
@@ -180,9 +190,10 @@ static NSString * const kTodayShownKey = @"FirstRechargeTodayShown";
|
||||
self.currentFirstRechargeData = model;
|
||||
[self saveCachedModel:model];
|
||||
|
||||
// 更新检查日期
|
||||
// 更新检查日期(针对当前用户)
|
||||
NSString *today = [self getTodayString];
|
||||
[[NSUserDefaults standardUserDefaults] setObject:today forKey:kLastCheckDateKey];
|
||||
NSString *userSpecificKey = [self getUserSpecificKey:kLastCheckDateKey];
|
||||
[[NSUserDefaults standardUserDefaults] setObject:today forKey:userSpecificKey];
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
|
||||
// 判断是否需要展示
|
||||
@@ -193,16 +204,13 @@ static NSString * const kTodayShownKey = @"FirstRechargeTodayShown";
|
||||
}
|
||||
|
||||
- (BOOL)shouldShowFirstRecharge:(FirstRechargeModel *)model {
|
||||
#if DEBUG
|
||||
return YES;
|
||||
#endif
|
||||
// 如果已经首充过,不展示
|
||||
if (model.chargeStatus) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
// 检查今天是否已经展示过
|
||||
NSString *shownDate = [[NSUserDefaults standardUserDefaults] objectForKey:kTodayShownKey];
|
||||
// 检查今天是否已经展示过(针对当前用户)
|
||||
NSString *shownDate = [self getTodayShownForCurrentUser];
|
||||
NSString *today = [self getTodayString];
|
||||
|
||||
return ![today isEqualToString:shownDate];
|
||||
@@ -224,16 +232,73 @@ static NSString * const kTodayShownKey = @"FirstRechargeTodayShown";
|
||||
return [formatter stringFromDate:[NSDate date]];
|
||||
}
|
||||
|
||||
#pragma mark - User Switch Detection
|
||||
|
||||
- (void)updateCurrentUserId {
|
||||
NSString *newUserId = [AccountInfoStorage instance].getUid;
|
||||
if (newUserId.length > 0) {
|
||||
self.currentUserId = newUserId;
|
||||
// 保存当前用户ID
|
||||
[[NSUserDefaults standardUserDefaults] setObject:newUserId forKey:kCurrentUserIdKey];
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)checkUserSwitch {
|
||||
NSString *savedUserId = [[NSUserDefaults standardUserDefaults] objectForKey:kCurrentUserIdKey];
|
||||
NSString *currentUserId = [AccountInfoStorage instance].getUid;
|
||||
|
||||
// 如果用户ID发生变化,说明用户切换了
|
||||
if (currentUserId.length > 0 &&
|
||||
savedUserId.length > 0 &&
|
||||
![currentUserId isEqualToString:savedUserId]) {
|
||||
|
||||
// 更新当前用户ID
|
||||
[self updateCurrentUserId];
|
||||
|
||||
// 清除当前缓存的模型数据(因为是新用户)
|
||||
self.currentFirstRechargeData = nil;
|
||||
|
||||
// 立即检查新用户的首充状态
|
||||
[self checkFirstRechargeStatus];
|
||||
} else if (currentUserId.length > 0 && savedUserId.length == 0) {
|
||||
// 首次登录的情况
|
||||
[self updateCurrentUserId];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - User-specific Storage
|
||||
|
||||
- (NSString *)getUserSpecificKey:(NSString *)baseKey {
|
||||
if (self.currentUserId.length == 0) {
|
||||
return baseKey;
|
||||
}
|
||||
return [NSString stringWithFormat:@"%@_%@", baseKey, self.currentUserId];
|
||||
}
|
||||
|
||||
- (NSString *)getTodayShownForCurrentUser {
|
||||
NSString *userSpecificKey = [self getUserSpecificKey:kTodayShownKey];
|
||||
return [[NSUserDefaults standardUserDefaults] objectForKey:userSpecificKey];
|
||||
}
|
||||
|
||||
- (void)setTodayShownForCurrentUser:(NSString *)date {
|
||||
NSString *userSpecificKey = [self getUserSpecificKey:kTodayShownKey];
|
||||
[[NSUserDefaults standardUserDefaults] setObject:date forKey:userSpecificKey];
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
}
|
||||
|
||||
- (void)saveCachedModel:(FirstRechargeModel *)model {
|
||||
if (model) {
|
||||
NSString *userSpecificKey = [self getUserSpecificKey:kFirstRechargeModelKey];
|
||||
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:model.toJSONObject requiringSecureCoding:NO error:nil];
|
||||
[[NSUserDefaults standardUserDefaults] setObject:data forKey:kFirstRechargeModelKey];
|
||||
[[NSUserDefaults standardUserDefaults] setObject:data forKey:userSpecificKey];
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)loadCachedModel {
|
||||
NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:kFirstRechargeModelKey];
|
||||
NSString *userSpecificKey = [self getUserSpecificKey:kFirstRechargeModelKey];
|
||||
NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:userSpecificKey];
|
||||
if (data) {
|
||||
NSDictionary *dict = [NSKeyedUnarchiver unarchivedObjectOfClass:[NSDictionary class] fromData:data error:nil];
|
||||
if (dict) {
|
||||
|
101
YuMi/Tools/MedalMediaDisplayManager.h
Normal file
101
YuMi/Tools/MedalMediaDisplayManager.h
Normal file
@@ -0,0 +1,101 @@
|
||||
//
|
||||
// MedalMediaDisplayManager.h
|
||||
// YuMi
|
||||
//
|
||||
// Created by AI on 2025/1/20.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@class VAPView, NetImageView, XPRoomGiftAnimationParser;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
* 媒体显示代理协议
|
||||
* 需要使用媒体显示功能的类实现此协议
|
||||
*/
|
||||
@protocol MedalMediaDisplayDelegate <NSObject>
|
||||
|
||||
@required
|
||||
/// 从数据模型中获取MP4 URL
|
||||
- (NSString * _Nullable)getMP4UrlFromModel:(id _Nullable)model;
|
||||
|
||||
/// 从数据模型中获取图片 URL
|
||||
- (NSString * _Nullable)getPicUrlFromModel:(id _Nullable)model;
|
||||
|
||||
/// 获取图片显示视图
|
||||
- (NetImageView *)getImageView;
|
||||
|
||||
/// 获取MP4播放视图
|
||||
- (VAPView *)getMP4View;
|
||||
|
||||
@optional
|
||||
/// 媒体显示状态更新回调
|
||||
- (void)onMediaDisplayUpdated:(BOOL)isMP4 success:(BOOL)success;
|
||||
|
||||
/// 获取默认占位图
|
||||
- (UIImage * _Nullable)getDefaultPlaceholderImage;
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
* 勋章媒体显示管理器
|
||||
* 统一处理MP4和PNG的显示逻辑
|
||||
*/
|
||||
@interface MedalMediaDisplayManager : NSObject
|
||||
|
||||
/// 代理对象
|
||||
@property (nonatomic, weak) id<MedalMediaDisplayDelegate> delegate;
|
||||
|
||||
/// 当前显示的数据模型
|
||||
@property (nonatomic, strong, nullable) id currentModel;
|
||||
|
||||
/// 可见性状态
|
||||
@property (nonatomic, assign) BOOL isVisible;
|
||||
|
||||
/// 当前媒体路径
|
||||
@property (nonatomic, copy, readonly, nullable) NSString *currentImagePath;
|
||||
@property (nonatomic, copy, readonly, nullable) NSString *currentMP4Path;
|
||||
|
||||
/**
|
||||
* 初始化方法
|
||||
* @param delegate 实现MedalMediaDisplayDelegate协议的对象
|
||||
*/
|
||||
- (instancetype)initWithDelegate:(id<MedalMediaDisplayDelegate>)delegate;
|
||||
|
||||
/**
|
||||
* 更新显示内容
|
||||
* @param model 数据模型
|
||||
*/
|
||||
- (void)updateDisplayWithModel:(id _Nullable)model;
|
||||
|
||||
/**
|
||||
* 可见性管理
|
||||
*/
|
||||
- (void)willDisplay;
|
||||
- (void)didEndDisplaying;
|
||||
|
||||
/**
|
||||
* 播放控制
|
||||
*/
|
||||
- (void)stopMP4Playback;
|
||||
- (void)pauseMP4Playback;
|
||||
- (void)resumeMP4Playback;
|
||||
|
||||
/**
|
||||
* 资源清理
|
||||
*/
|
||||
- (void)cleanupResources;
|
||||
|
||||
/**
|
||||
* 应用生命周期通知处理
|
||||
*/
|
||||
- (void)handleAppDidEnterBackground;
|
||||
- (void)handleAppWillEnterForeground;
|
||||
- (void)handleMemoryWarning;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
328
YuMi/Tools/MedalMediaDisplayManager.m
Normal file
328
YuMi/Tools/MedalMediaDisplayManager.m
Normal file
@@ -0,0 +1,328 @@
|
||||
//
|
||||
// MedalMediaDisplayManager.m
|
||||
// YuMi
|
||||
//
|
||||
// Created by AI on 2025/1/20.
|
||||
//
|
||||
|
||||
#import "MedalMediaDisplayManager.h"
|
||||
#import <QGVAPWrapView.h>
|
||||
#import "XPRoomGiftAnimationParser.h"
|
||||
#import "NSString+XPExtension.h"
|
||||
#import "UIImageConstant.h"
|
||||
|
||||
@interface MedalMediaDisplayManager () <HWDMP4PlayDelegate>
|
||||
|
||||
@property (nonatomic, copy, readwrite, nullable) NSString *currentImagePath;
|
||||
@property (nonatomic, copy, readwrite, nullable) NSString *currentMP4Path;
|
||||
@property (nonatomic, strong) XPRoomGiftAnimationParser *mp4Parser;
|
||||
@property (nonatomic, assign) NSInteger mp4PlaybackTag; // 播放状态标记
|
||||
|
||||
@end
|
||||
|
||||
@implementation MedalMediaDisplayManager
|
||||
|
||||
#pragma mark - 初始化
|
||||
|
||||
- (instancetype)initWithDelegate:(id<MedalMediaDisplayDelegate>)delegate {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_delegate = delegate;
|
||||
_isVisible = YES;
|
||||
_mp4PlaybackTag = 0;
|
||||
[self setupNotifications];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[self cleanupResources];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
NSLog(@"MedalMediaDisplayManager dealloc");
|
||||
}
|
||||
|
||||
#pragma mark - 公共接口
|
||||
|
||||
- (void)updateDisplayWithModel:(id)model {
|
||||
self.currentModel = model;
|
||||
[self handleMediaDisplayWithModel:model];
|
||||
}
|
||||
|
||||
- (void)willDisplay {
|
||||
self.isVisible = YES;
|
||||
[self resumeMP4PlaybackIfNeeded];
|
||||
}
|
||||
|
||||
- (void)didEndDisplaying {
|
||||
self.isVisible = NO;
|
||||
[self pauseMP4Playback];
|
||||
}
|
||||
|
||||
- (void)stopMP4Playback {
|
||||
VAPView *mp4View = [self.delegate getMP4View];
|
||||
if (mp4View) {
|
||||
[mp4View stopHWDMP4];
|
||||
self.mp4PlaybackTag = 0;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)pauseMP4Playback {
|
||||
VAPView *mp4View = [self.delegate getMP4View];
|
||||
if (mp4View && !mp4View.hidden) {
|
||||
[mp4View pauseHWDMP4];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)resumeMP4Playback {
|
||||
[self resumeMP4PlaybackIfNeeded];
|
||||
}
|
||||
|
||||
- (void)cleanupResources {
|
||||
[self stopMP4Playback];
|
||||
self.mp4Parser = nil;
|
||||
self.currentImagePath = nil;
|
||||
self.currentMP4Path = nil;
|
||||
self.currentModel = nil;
|
||||
}
|
||||
|
||||
#pragma mark - 核心媒体处理逻辑
|
||||
|
||||
- (void)handleMediaDisplayWithModel:(id)model {
|
||||
if (!model || !self.delegate) {
|
||||
[self showDefaultPlaceholder];
|
||||
return;
|
||||
}
|
||||
|
||||
NSString *mp4Url = [self.delegate getMP4UrlFromModel:model];
|
||||
NSString *picUrl = [self.delegate getPicUrlFromModel:model];
|
||||
|
||||
// 优先判断 MP4 URL
|
||||
if (![NSString isEmpty:mp4Url] && [self isValidMP4URL:mp4Url]) {
|
||||
[self setMp4Path:mp4Url];
|
||||
return;
|
||||
}
|
||||
|
||||
// MP4 URL 无效,检查图片 URL
|
||||
if (![NSString isEmpty:picUrl]) {
|
||||
if ([self isValidMP4URL:picUrl]) {
|
||||
// picUrl 实际上是 MP4(兼容旧逻辑)
|
||||
[self setMp4Path:picUrl];
|
||||
return;
|
||||
} else if ([NSString isValidImageURL:picUrl]) {
|
||||
// 有效的图片 URL
|
||||
[self setImagePath:picUrl];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 都无效,显示默认占位图
|
||||
[self showDefaultPlaceholder];
|
||||
}
|
||||
|
||||
- (void)setImagePath:(NSString *)imagePath {
|
||||
[self stopMP4Playback];
|
||||
|
||||
self.currentImagePath = imagePath;
|
||||
self.currentMP4Path = nil;
|
||||
|
||||
VAPView *mp4View = [self.delegate getMP4View];
|
||||
NetImageView *imageView = [self.delegate getImageView];
|
||||
|
||||
mp4View.hidden = YES;
|
||||
imageView.hidden = NO;
|
||||
imageView.imageUrl = imagePath ?: @"";
|
||||
|
||||
[self notifyDisplayUpdated:NO success:![NSString isEmpty:imagePath]];
|
||||
}
|
||||
|
||||
- (void)setMp4Path:(NSString *)mp4Path {
|
||||
if ([NSString isEmpty:mp4Path]) {
|
||||
[self showDefaultPlaceholder];
|
||||
return;
|
||||
}
|
||||
|
||||
[self stopMP4Playback];
|
||||
|
||||
self.currentMP4Path = mp4Path;
|
||||
self.currentImagePath = nil;
|
||||
|
||||
VAPView *mp4View = [self.delegate getMP4View];
|
||||
NetImageView *imageView = [self.delegate getImageView];
|
||||
|
||||
mp4View.hidden = NO;
|
||||
imageView.hidden = YES;
|
||||
|
||||
if (!self.mp4Parser) {
|
||||
self.mp4Parser = [[XPRoomGiftAnimationParser alloc] init];
|
||||
}
|
||||
|
||||
@kWeakify(self);
|
||||
[self.mp4Parser parseWithURL:mp4Path
|
||||
completionBlock:^(NSString * _Nullable videoUrl) {
|
||||
@kStrongify(self);
|
||||
if (![NSString isEmpty:videoUrl]) {
|
||||
self.mp4PlaybackTag = 1; // 标记已准备好播放
|
||||
|
||||
if (self.isVisible) {
|
||||
[self startMP4PlaybackWithURL:videoUrl];
|
||||
}
|
||||
}
|
||||
} failureBlock:^(NSError * _Nullable error) {
|
||||
@kStrongify(self);
|
||||
NSLog(@"[MedalMediaDisplayManager] Failed to parse mp4: %@", error);
|
||||
[self handleMP4FailureWithFallback];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)startMP4PlaybackWithURL:(NSString *)videoUrl {
|
||||
if ([NSString isEmpty:videoUrl] || !self.delegate) {
|
||||
return;
|
||||
}
|
||||
|
||||
VAPView *mp4View = [self.delegate getMP4View];
|
||||
if (mp4View && !mp4View.hidden) {
|
||||
[mp4View playHWDMP4:videoUrl repeatCount:-1 delegate:self];
|
||||
[self notifyDisplayUpdated:YES success:YES];
|
||||
NSLog(@"[MedalMediaDisplayManager] Started MP4 playback: %@", videoUrl);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)handleMP4FailureWithFallback {
|
||||
if (!self.delegate || !self.currentModel) {
|
||||
[self showDefaultPlaceholder];
|
||||
return;
|
||||
}
|
||||
|
||||
// MP4 失败,尝试降级到图片
|
||||
NSString *picUrl = [self.delegate getPicUrlFromModel:self.currentModel];
|
||||
if (![NSString isEmpty:picUrl] && [NSString isValidImageURL:picUrl]) {
|
||||
[self setImagePath:picUrl];
|
||||
} else {
|
||||
[self showDefaultPlaceholder];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)showDefaultPlaceholder {
|
||||
[self stopMP4Playback];
|
||||
|
||||
VAPView *mp4View = [self.delegate getMP4View];
|
||||
NetImageView *imageView = [self.delegate getImageView];
|
||||
|
||||
mp4View.hidden = YES;
|
||||
imageView.hidden = NO;
|
||||
imageView.imageUrl = @"";
|
||||
|
||||
// 获取默认占位图
|
||||
UIImage *placeholderImage = nil;
|
||||
if ([self.delegate respondsToSelector:@selector(getDefaultPlaceholderImage)]) {
|
||||
placeholderImage = [self.delegate getDefaultPlaceholderImage];
|
||||
}
|
||||
if (!placeholderImage) {
|
||||
placeholderImage = [UIImageConstant defaultEmptyPlaceholder];
|
||||
}
|
||||
imageView.image = placeholderImage;
|
||||
|
||||
[self notifyDisplayUpdated:NO success:NO];
|
||||
}
|
||||
|
||||
- (void)resumeMP4PlaybackIfNeeded {
|
||||
if (!self.isVisible || [NSString isEmpty:self.currentMP4Path]) {
|
||||
return;
|
||||
}
|
||||
|
||||
VAPView *mp4View = [self.delegate getMP4View];
|
||||
if (mp4View && !mp4View.hidden) {
|
||||
if (self.mp4PlaybackTag == 1) {
|
||||
// 已准备好但尚未播放,重新解析并播放
|
||||
@kWeakify(self);
|
||||
[self.mp4Parser parseWithURL:self.currentMP4Path
|
||||
completionBlock:^(NSString * _Nullable videoUrl) {
|
||||
@kStrongify(self);
|
||||
if (![NSString isEmpty:videoUrl] && self.isVisible) {
|
||||
[self startMP4PlaybackWithURL:videoUrl];
|
||||
}
|
||||
} failureBlock:^(NSError * _Nullable error) {
|
||||
@kStrongify(self);
|
||||
[self handleMP4FailureWithFallback];
|
||||
}];
|
||||
} else {
|
||||
// 恢复暂停的播放
|
||||
[mp4View resumeHWDMP4];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - 辅助方法
|
||||
|
||||
- (BOOL)isValidMP4URL:(NSString *)url {
|
||||
if ([NSString isEmpty:url]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
NSString *lowercaseUrl = [url lowercaseString];
|
||||
return [lowercaseUrl hasSuffix:@".mp4"] ||
|
||||
[lowercaseUrl containsString:@"mp4"] ||
|
||||
[lowercaseUrl containsString:@"video"];
|
||||
}
|
||||
|
||||
- (void)notifyDisplayUpdated:(BOOL)isMP4 success:(BOOL)success {
|
||||
if ([self.delegate respondsToSelector:@selector(onMediaDisplayUpdated:success:)]) {
|
||||
[self.delegate onMediaDisplayUpdated:isMP4 success:success];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - 通知处理
|
||||
|
||||
- (void)setupNotifications {
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(handleAppDidEnterBackground)
|
||||
name:UIApplicationDidEnterBackgroundNotification
|
||||
object:nil];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(handleAppWillEnterForeground)
|
||||
name:UIApplicationWillEnterForegroundNotification
|
||||
object:nil];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(handleMemoryWarning)
|
||||
name:UIApplicationDidReceiveMemoryWarningNotification
|
||||
object:nil];
|
||||
}
|
||||
|
||||
- (void)handleAppDidEnterBackground {
|
||||
[self pauseMP4Playback];
|
||||
}
|
||||
|
||||
- (void)handleAppWillEnterForeground {
|
||||
if (self.isVisible) {
|
||||
[self resumeMP4PlaybackIfNeeded];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)handleMemoryWarning {
|
||||
if (!self.isVisible) {
|
||||
[self stopMP4Playback];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - HWDMP4PlayDelegate
|
||||
|
||||
- (BOOL)shouldStartPlayMP4:(VAPView *)container config:(QGVAPConfigModel *)config {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)viewDidFinishPlayMP4:(NSInteger)totalFrameCount view:(VAPView *)container {
|
||||
// MP4 播放完成,循环播放会自动重新开始
|
||||
}
|
||||
|
||||
- (void)viewDidStopPlayMP4:(NSInteger)lastFrameIndex view:(VAPView *)container {
|
||||
// MP4 播放停止
|
||||
}
|
||||
|
||||
- (void)viewDidFailPlayMP4:(NSError *)error {
|
||||
NSLog(@"[MedalMediaDisplayManager] MP4 播放失败: %@", error);
|
||||
[self handleMP4FailureWithFallback];
|
||||
}
|
||||
|
||||
@end
|
@@ -2941,8 +2941,8 @@ ineHeadView12" = "الحمل";
|
||||
"LoginBindPhoneViewController2" = "ربط رقم الهاتف المحمول";
|
||||
|
||||
"MvpViewController0" = "وقت الإلغاء: %@";
|
||||
"MvpViewController1" = "%@\n\nيرجى الاتصال بخدمة العملاء (WeChat: mxyz2050) للحصول على استفسارات";
|
||||
"MvpViewController2" = "تم إلغاء تسجيل الحساب";
|
||||
"MvpViewController1.1" = "@%\n\nيرجى الاتصال بخدمة العملاء (WeChat: mxyz2050) للحصول على استفسارات";
|
||||
"MvpViewController1.2" = "يرجى الاتصال بخدمة العملاء (WeChat: mxyz2050) للحصول على استفسارات";
|
||||
"MvpViewController3" = "من أجل خلق بيئة إنترنت آمنة أكثر\nحماية ممتلكاتك وممتلكات الآخرين\nيرجى تقديم التحقق الهوية أولا";
|
||||
|
||||
"MvpViewController5" = "التحقق من الهوية";
|
||||
@@ -4206,3 +4206,24 @@ ineHeadView12" = "الحمل";
|
||||
"20.20.59_text_34" = "تم التقديم بنجاح";
|
||||
"20.20.59_text_35" = "تم الاشتراك بنجاح";
|
||||
"20.20.59_text_36" = "تم الإلغاء بنجاح";
|
||||
|
||||
"20.20.61_text_1" = "ميدالياتي";
|
||||
"20.20.61_text_2" = "حامل الميدالية";
|
||||
"20.20.61_text_3" = "ميداليات المهام";
|
||||
"20.20.61_text_4" = "ميداليات الأنشطة";
|
||||
"20.20.61_text_5" = "ميداليات المجد";
|
||||
"20.20.61_text_6" = "لا ترتدي أي ميداليات";
|
||||
"20.20.61_text_7.1" = "لم تستلم أي ميداليات";
|
||||
"20.20.61_text_7.2" = "لم تستلم أي ميداليات\nاذهب إلى مربع الميداليات وتحقق!";
|
||||
"20.20.61_text_8" = "تاريخ الانتهاء:%@";
|
||||
"20.20.61_text_9" = "دائمًا";
|
||||
"20.20.61_text_10" = "مربع الميداليات";
|
||||
"20.20.61_text_11" = "قاعة مشاهير الميداليات";
|
||||
"20.20.61_text_12" = "المالك القوي";
|
||||
"20.20.61_text_13" = "عرض ميدالياته";
|
||||
"20.20.61_text_14" = "%@ ميدالية";
|
||||
"20.20.61_text_15" = "قم بترقية VIP للحصول على المزيد من فتحات عرض الميداليات!";
|
||||
"20.20.61_text_16" = "ميدالياتك ممتلئة!\nاضبطها أولاً ثم أضف المزيد!";
|
||||
"20.20.61_text_17" = "نصيحة مقعد الميدالية";
|
||||
"20.20.61_text_18" = "قم بالترقية الآن!";
|
||||
"20.20.61_text_19" = "بونص";
|
||||
|
@@ -2549,6 +2549,8 @@
|
||||
|
||||
"MvpViewController0" = "Logoff time: %@";
|
||||
"MvpViewController1" = "%@\n\nPlease contact customer service (WeChat: mxyz2050) for inquiries.";
|
||||
"MvpViewController1.1" = "%@\n\nPlease contact customer service (WeChat: mxyz2050) for inquiries.";
|
||||
"MvpViewController1.2" = "Please contact customer service (WeChat: mxyz2050) for inquiries.";
|
||||
"MvpViewController2" = "This account has been logged off";
|
||||
"MvpViewController3" = "In order to create a safer online environment\nand protect the property safety of you and others,\nplease complete real-name authentication first";
|
||||
|
||||
@@ -3991,3 +3993,24 @@
|
||||
"20.20.59_text_34" = "Submission Successful";
|
||||
"20.20.59_text_35" = "Sub successful";
|
||||
"20.20.59_text_36" = "Cancel successful";
|
||||
|
||||
"20.20.61_text_1" = "My Medals";
|
||||
"20.20.61_text_2" = "Medal Wearing";
|
||||
"20.20.61_text_3" = "Task Medals";
|
||||
"20.20.61_text_4" = "Activity Medals";
|
||||
"20.20.61_text_5" = "Glory Medals";
|
||||
"20.20.61_text_6" = "You are not wearing any medals";
|
||||
"20.20.61_text_7.1" = "You have not received any medals";
|
||||
"20.20.61_text_7.2" = "You have not received any medals\nGo to the medal square and check it out!";
|
||||
"20.20.61_text_8" = "Expiration time:%@";
|
||||
"20.20.61_text_9" = "Forever";
|
||||
"20.20.61_text_10" = "Medal Square";
|
||||
"20.20.61_text_11" = "Medal Hall of Fame";
|
||||
"20.20.61_text_12" = "Powerful Owner";
|
||||
"20.20.61_text_13" = "View his medals";
|
||||
"20.20.61_text_14" = "%@'s medal";
|
||||
"20.20.61_text_15" = "Upgrade VIP to get more medal display slots!";
|
||||
"20.20.61_text_16" = "Your medals are full!\nAdjust first and then add more!";
|
||||
"20.20.61_text_17" = "Medal Seat Tip";
|
||||
"20.20.61_text_18" = "Upgrade now!";
|
||||
"20.20.61_text_19" = "Bonus";
|
||||
|
@@ -2224,6 +2224,8 @@
|
||||
|
||||
"MvpViewController0" = "Oturumu kapatma zamanı: %@";
|
||||
"MvpViewController1" = "%@\n\nMüşteri hizmetleriyle iletişime geçin (WeChat: mxyz2050) danışın";
|
||||
"MvpViewController1.1" = "%@\n\nMüşteri hizmetleriyle iletişime geçin (WeChat: mxyz2050) danışın";
|
||||
"MvpViewController1.2" = "Müşteri hizmetleriyle iletişime geçin (WeChat: mxyz2050) danışın";
|
||||
"MvpViewController2" = "Bu hesap kapatıldı";
|
||||
"MvpViewController3" = "Daha güvenli bir ağ ortamı oluşturmak ve sizin ve diğerlerinin mülk güvenliğini korumak için\nlütfen önce kimlik doğrulaması yapın";
|
||||
|
||||
@@ -3784,3 +3786,24 @@
|
||||
"20.20.59_text_34" = "Gönderim Başarılı";
|
||||
"20.20.59_text_35" = "Alt başarılı";
|
||||
"20.20.59_text_36" = "İptal başarılı";
|
||||
|
||||
"20.20.61_text_1" = "Madalyalarım";
|
||||
"20.20.61_text_2" = "Madalya Takma";
|
||||
"20.20.61_text_3" = "Görev Madalyaları";
|
||||
"20.20.61_text_4" = "Etkinlik Madalyaları";
|
||||
"20.20.61_text_5" = "Şan madalyaları";
|
||||
"20.20.61_text_6" = "Hiçbir madalya takmıyorsunuz";
|
||||
"20.20.61_text_7.1" = "Hiçbir madalya almadınız";
|
||||
"20.20.61_text_7.2" = "Hiçbir madalya almadınız\nMadalya karesine gidin ve kontrol edin!";
|
||||
"20.20.61_text_8" = "Son kullanma tarihi:%@";
|
||||
"20.20.61_text_9" = "Sonsuza kadar";
|
||||
"20.20.61_text_10" = "Madalya Karesi";
|
||||
"20.20.61_text_11" = "Madalya Şeref Salonu";
|
||||
"20.20.61_text_12" = "Güçlü Sahip";
|
||||
"20.20.61_text_13" = "Madalyalarını görüntüle";
|
||||
"20.20.61_text_14" = "%@'ın madalyası";
|
||||
"20.20.61_text_15" = "Daha fazla madalya sergileme yuvası elde etmek için VIP'yi yükseltin!";
|
||||
"20.20.61_text_16" = "Madalyalarınız dolu!\nÖnce ayarlayın ve sonra daha fazlasını ekleyin!";
|
||||
"20.20.61_text_17" = "Madalya Koltuğu İpucu";
|
||||
"20.20.61_text_18" = "Şimdi yükseltin!";
|
||||
"20.20.61_text_19" = "Bonus";
|
||||
|
@@ -2263,7 +2263,8 @@
|
||||
"LoginBindPhoneViewController2" = "綁定手機號";
|
||||
|
||||
"MvpViewController0" = "註銷時間: %@";
|
||||
"MvpViewController1" = "%@\n\n請聯繫客服(微信:mxyz2050)咨詢哦";
|
||||
"MvpViewController1.1" = "%@\n\n請聯繫客服(微信:mxyz2050)咨詢哦";
|
||||
"MvpViewController1.2" = "請聯繫客服(微信:mxyz2050)咨詢哦";
|
||||
"MvpViewController2" = "該賬號已註銷";
|
||||
"MvpViewController3" = "為了營造更安全的網絡環境\n保護您和他人的財產安全\n請先進行實名認證";
|
||||
|
||||
@@ -3657,17 +3658,23 @@
|
||||
"20.20.59_text_35" = "訂閱成功";
|
||||
"20.20.59_text_36" = "取消成功";
|
||||
|
||||
"20.20.61_text_1" = "My Medals";
|
||||
"20.20.61_text_2" = "Wearing";
|
||||
"20.20.61_text_3" = "Task Medals";
|
||||
"20.20.61_text_4" = "Activity Medals";
|
||||
"20.20.61_text_5" = "Glory Medals";
|
||||
"20.20.61_text_6" = "You are not wearing any medals";
|
||||
"20.20.61_text_7" = "You have not received any medals Go to the medal square and check it out!";
|
||||
"20.20.61_text_8" = "Expiration time:%@";
|
||||
"20.20.61_text_9" = "Forever";
|
||||
"20.20.61_text_10" = "Medals Square";
|
||||
"20.20.61_text_11" = "Medal Hall of Fame";
|
||||
"20.20.61_text_12" = "Powerful Owner";
|
||||
"20.20.61_text_13" = "View his medals";
|
||||
"20.20.61_text_14" = "%@'s medal";
|
||||
"20.20.61_text_1" = "我的獎牌";
|
||||
"20.20.61_text_2" = "配戴獎牌";
|
||||
"20.20.61_text_3" = "任務獎章";
|
||||
"20.20.61_text_4" = "活動獎牌";
|
||||
"20.20.61_text_5" = "榮耀勳章";
|
||||
"20.20.61_text_6" = "你沒有戴任何獎牌";
|
||||
"20.20.61_text_7.1" = "您尚未獲得任何勳章";
|
||||
"20.20.61_text_7.2" = "您尚未獲得任何勳章\n去獎牌廣場看看吧!";
|
||||
"20.20.61_text_8" = "到期時間:%@";
|
||||
"20.20.61_text_9" = "永遠";
|
||||
"20.20.61_text_10" = "獎牌廣場";
|
||||
"20.20.61_text_11" = "獎章名人堂";
|
||||
"20.20.61_text_12" = "強大的拥有者";
|
||||
"20.20.61_text_13" = "看他的獎牌";
|
||||
"20.20.61_text_14" = "%@的勳章";
|
||||
"20.20.61_text_15" = "升級VIP獲得更多勳章展示位!";
|
||||
"20.20.61_text_16" = "你的勳章已滿!\n先調整,然後再增加更多!";
|
||||
"20.20.61_text_17" = "獎牌座位提示";
|
||||
"20.20.61_text_18" = "立即升級!";
|
||||
"20.20.61_text_19" = "額外獎勵";
|
||||
|
Reference in New Issue
Block a user