Commit e062205a by suolong

礼物互动完成

parent 9155725f
Showing with 809 additions and 87 deletions
...@@ -100,6 +100,8 @@ ...@@ -100,6 +100,8 @@
// 更新直播间互动游戏开关状态socket // 更新直播间互动游戏开关状态socket
#define ROOM_CID_liveInteractionGameStateDidChanged 20204 #define ROOM_CID_liveInteractionGameStateDidChanged 20204
// 更新直播间礼物互动开关状态socket(主播/观众都会收到)
#define ROOM_CID_giftInteractionStateDidChanged 20205
#define ROOM_CID_LINKMIC_SENDINVIT 30001 // 主播发送连麦邀请 #define ROOM_CID_LINKMIC_SENDINVIT 30001 // 主播发送连麦邀请
#define ROOM_CID_LINKMIC_REPLYINVIT 30002 // 用户回复连麦邀请 #define ROOM_CID_LINKMIC_REPLYINVIT 30002 // 用户回复连麦邀请
...@@ -116,6 +118,7 @@ ...@@ -116,6 +118,7 @@
#define USER_ACCOUNT_CHANGE 12000 // 推送用户账户发生变化 #define USER_ACCOUNT_CHANGE 12000 // 推送用户账户发生变化
#define ROOM_CID_GIFT_INTERACT_TASK_CHANGED 12002 // 礼物互动任务达成变化 #define ROOM_CID_GIFT_INTERACT_TASK_CHANGED 12002 // 礼物互动任务达成变化
#define ROOM_CID_GIFT_INTERACT_TASK_LIST_REFRESH 12003 // 礼物互动任务列表刷新(用于观众端面板直刷)
#define ROOM_CID_REALTIME_ACTIVITY_INFO 10091 // 直播间实时活动 #define ROOM_CID_REALTIME_ACTIVITY_INFO 10091 // 直播间实时活动
#define ROOM_CID_LIVE_ALERT 10090 // 接收到直播弹窗通知 #define ROOM_CID_LIVE_ALERT 10090 // 接收到直播弹窗通知
...@@ -132,5 +135,3 @@ ...@@ -132,5 +135,3 @@
...@@ -1668,6 +1668,7 @@ ...@@ -1668,6 +1668,7 @@
BED65A792C5B745F00668116 /* FUSLiveFunctionView.h in Headers */ = {isa = PBXBuildFile; fileRef = BED657A42C5B745D00668116 /* FUSLiveFunctionView.h */; }; BED65A792C5B745F00668116 /* FUSLiveFunctionView.h in Headers */ = {isa = PBXBuildFile; fileRef = BED657A42C5B745D00668116 /* FUSLiveFunctionView.h */; };
BED65A7A2C5B745F00668116 /* FUSLiveFunctionView.m in Sources */ = {isa = PBXBuildFile; fileRef = BED657A52C5B745D00668116 /* FUSLiveFunctionView.m */; }; BED65A7A2C5B745F00668116 /* FUSLiveFunctionView.m in Sources */ = {isa = PBXBuildFile; fileRef = BED657A52C5B745D00668116 /* FUSLiveFunctionView.m */; };
C0A1B2C32F6A000100AAAA03 /* FUSLiveGiftInteractTaskPanelView.m in Sources */ = {isa = PBXBuildFile; fileRef = C0A1B2C32F6A000100AAAA02 /* FUSLiveGiftInteractTaskPanelView.m */; }; C0A1B2C32F6A000100AAAA03 /* FUSLiveGiftInteractTaskPanelView.m in Sources */ = {isa = PBXBuildFile; fileRef = C0A1B2C32F6A000100AAAA02 /* FUSLiveGiftInteractTaskPanelView.m */; };
C0A1B2C32F6A000100AAAA06 /* FUSLiveGiftInteractAudiencePanelView.m in Sources */ = {isa = PBXBuildFile; fileRef = C0A1B2C32F6A000100AAAA05 /* FUSLiveGiftInteractAudiencePanelView.m */; };
BED65A7B2C5B745F00668116 /* FUSLiveLoadingView.h in Headers */ = {isa = PBXBuildFile; fileRef = BED657A72C5B745D00668116 /* FUSLiveLoadingView.h */; }; BED65A7B2C5B745F00668116 /* FUSLiveLoadingView.h in Headers */ = {isa = PBXBuildFile; fileRef = BED657A72C5B745D00668116 /* FUSLiveLoadingView.h */; };
BED65A7C2C5B745F00668116 /* FUSLiveLoadingView.m in Sources */ = {isa = PBXBuildFile; fileRef = BED657A82C5B745D00668116 /* FUSLiveLoadingView.m */; }; BED65A7C2C5B745F00668116 /* FUSLiveLoadingView.m in Sources */ = {isa = PBXBuildFile; fileRef = BED657A82C5B745D00668116 /* FUSLiveLoadingView.m */; };
BED65A7E2C5B745F00668116 /* FUSLiveMinimizeView.h in Headers */ = {isa = PBXBuildFile; fileRef = BED657AB2C5B745D00668116 /* FUSLiveMinimizeView.h */; }; BED65A7E2C5B745F00668116 /* FUSLiveMinimizeView.h in Headers */ = {isa = PBXBuildFile; fileRef = BED657AB2C5B745D00668116 /* FUSLiveMinimizeView.h */; };
...@@ -4093,6 +4094,8 @@ ...@@ -4093,6 +4094,8 @@
BED657A52C5B745D00668116 /* FUSLiveFunctionView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FUSLiveFunctionView.m; sourceTree = "<group>"; }; BED657A52C5B745D00668116 /* FUSLiveFunctionView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FUSLiveFunctionView.m; sourceTree = "<group>"; };
C0A1B2C32F6A000100AAAA01 /* FUSLiveGiftInteractTaskPanelView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FUSLiveGiftInteractTaskPanelView.h; sourceTree = "<group>"; }; C0A1B2C32F6A000100AAAA01 /* FUSLiveGiftInteractTaskPanelView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FUSLiveGiftInteractTaskPanelView.h; sourceTree = "<group>"; };
C0A1B2C32F6A000100AAAA02 /* FUSLiveGiftInteractTaskPanelView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FUSLiveGiftInteractTaskPanelView.m; sourceTree = "<group>"; }; C0A1B2C32F6A000100AAAA02 /* FUSLiveGiftInteractTaskPanelView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FUSLiveGiftInteractTaskPanelView.m; sourceTree = "<group>"; };
C0A1B2C32F6A000100AAAA04 /* FUSLiveGiftInteractAudiencePanelView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FUSLiveGiftInteractAudiencePanelView.h; sourceTree = "<group>"; };
C0A1B2C32F6A000100AAAA05 /* FUSLiveGiftInteractAudiencePanelView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FUSLiveGiftInteractAudiencePanelView.m; sourceTree = "<group>"; };
BED657A72C5B745D00668116 /* FUSLiveLoadingView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FUSLiveLoadingView.h; sourceTree = "<group>"; }; BED657A72C5B745D00668116 /* FUSLiveLoadingView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FUSLiveLoadingView.h; sourceTree = "<group>"; };
BED657A82C5B745D00668116 /* FUSLiveLoadingView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FUSLiveLoadingView.m; sourceTree = "<group>"; }; BED657A82C5B745D00668116 /* FUSLiveLoadingView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FUSLiveLoadingView.m; sourceTree = "<group>"; };
BED657A92C5B745D00668116 /* FUSLiveLoadingView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = FUSLiveLoadingView.xib; sourceTree = "<group>"; }; BED657A92C5B745D00668116 /* FUSLiveLoadingView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = FUSLiveLoadingView.xib; sourceTree = "<group>"; };
...@@ -7428,6 +7431,8 @@ ...@@ -7428,6 +7431,8 @@
children = ( children = (
C0A1B2C32F6A000100AAAA01 /* FUSLiveGiftInteractTaskPanelView.h */, C0A1B2C32F6A000100AAAA01 /* FUSLiveGiftInteractTaskPanelView.h */,
C0A1B2C32F6A000100AAAA02 /* FUSLiveGiftInteractTaskPanelView.m */, C0A1B2C32F6A000100AAAA02 /* FUSLiveGiftInteractTaskPanelView.m */,
C0A1B2C32F6A000100AAAA04 /* FUSLiveGiftInteractAudiencePanelView.h */,
C0A1B2C32F6A000100AAAA05 /* FUSLiveGiftInteractAudiencePanelView.m */,
); );
path = GiftInteract; path = GiftInteract;
sourceTree = "<group>"; sourceTree = "<group>";
...@@ -10774,6 +10779,7 @@ ...@@ -10774,6 +10779,7 @@
BED658BA2C5B745E00668116 /* FUSHalfWebViewCollectionViewCell.m in Sources */, BED658BA2C5B745E00668116 /* FUSHalfWebViewCollectionViewCell.m in Sources */,
BED65A7A2C5B745F00668116 /* FUSLiveFunctionView.m in Sources */, BED65A7A2C5B745F00668116 /* FUSLiveFunctionView.m in Sources */,
C0A1B2C32F6A000100AAAA03 /* FUSLiveGiftInteractTaskPanelView.m in Sources */, C0A1B2C32F6A000100AAAA03 /* FUSLiveGiftInteractTaskPanelView.m in Sources */,
C0A1B2C32F6A000100AAAA06 /* FUSLiveGiftInteractAudiencePanelView.m in Sources */,
004773412F5EBADE00E46A79 /* FUSNewUserSevenDayCheckInControl.swift in Sources */, 004773412F5EBADE00E46A79 /* FUSNewUserSevenDayCheckInControl.swift in Sources */,
BED658FF2C5B745E00668116 /* FUSLiveChatInputBulletsListCell.m in Sources */, BED658FF2C5B745E00668116 /* FUSLiveChatInputBulletsListCell.m in Sources */,
BED6599A2C5B745E00668116 /* FUSAgoraHelper.m in Sources */, BED6599A2C5B745E00668116 /* FUSAgoraHelper.m in Sources */,
{
"images" : [
{
"filename" : "Live_bottom_leftArrow.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Live_bottom_leftArrow@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Live_bottom_leftArrow@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "Live_bottom_liveTopic.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Live_bottom_liveTopic@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Live_bottom_liveTopic@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
...@@ -97,7 +97,6 @@ static NSInteger const FUSLiveGiftInteractMaxItemCount = 6; ...@@ -97,7 +97,6 @@ static NSInteger const FUSLiveGiftInteractMaxItemCount = 6;
if (roomInfo.stateSwitch) { if (roomInfo.stateSwitch) {
roomInfo.stateSwitch.giftinteractionstate = switchState; roomInfo.stateSwitch.giftinteractionstate = switchState;
} }
[[NSNotificationCenter defaultCenter] postNotificationName:@"FUSGiftInteractSwitchDidChangeNotification" object:nil userInfo:@{@"switchState": @(switchState)}];
[weakCell fus_setupWithEnabled:switchState]; [weakCell fus_setupWithEnabled:switchState];
[weakCell fus_setSwitchUserInteractionEnabled:YES]; [weakCell fus_setSwitchUserInteractionEnabled:YES];
} failure:^(NSString *msg, NSInteger code) { } failure:^(NSString *msg, NSInteger code) {
......
...@@ -1158,6 +1158,34 @@ NS_ASSUME_NONNULL_BEGIN ...@@ -1158,6 +1158,34 @@ NS_ASSUME_NONNULL_BEGIN
succeed:(void (^)(NSDictionary *dataDict))succeed succeed:(void (^)(NSDictionary *dataDict))succeed
failure:(void (^)(NSString *msg, NSInteger code))failure; failure:(void (^)(NSString *msg, NSInteger code))failure;
/// 礼物互动行为-主播更新任务状态(完成)
/// @param uid 用户ID
/// @param roomId 房间ID
/// @param channelId 频道ID
/// @param taskId 任务ID
/// @param status 状态(1:已完成)
/// @param succeed 成功回调
/// @param failure 失败回调
+ (void)fus_requestGiftInteractTaskCompleteWithUid:(NSString *)uid
roomId:(NSString *)roomId
channelId:(NSString *)channelId
taskId:(NSString *)taskId
status:(NSInteger)status
succeed:(void (^)(void))succeed
failure:(void (^)(NSString *msg, NSInteger code))failure;
/// 礼物互动行为-用户获取列表(观众端)
/// @param uid 用户ID
/// @param roomId 房间ID
/// @param channelId 频道ID
/// @param succeed 成功回调(返回 dataList 原始数组)
/// @param failure 失败回调
+ (void)fus_requestGiftInteractItemDataListWithUid:(NSString *)uid
roomId:(NSString *)roomId
channelId:(NSString *)channelId
succeed:(void (^)(NSArray *dataList))succeed
failure:(void (^)(NSString *msg, NSInteger code))failure;
/// 礼物互动行为-管理获取配置列表 /// 礼物互动行为-管理获取配置列表
/// @param uid 用户ID /// @param uid 用户ID
/// @param roomId 房间ID /// @param roomId 房间ID
......
...@@ -149,6 +149,69 @@ ...@@ -149,6 +149,69 @@
} }
}]; }];
} }
/// 礼物互动行为-主播更新任务状态(完成)
+ (void)fus_requestGiftInteractTaskCompleteWithUid:(NSString *)uid
roomId:(NSString *)roomId
channelId:(NSString *)channelId
taskId:(NSString *)taskId
status:(NSInteger)status
succeed:(void (^)(void))succeed
failure:(void (^)(NSString *msg, NSInteger code))failure {
if ([NSString isNullWithString:uid] ||
[NSString isNullWithString:roomId] ||
[NSString isNullWithString:channelId] ||
[NSString isNullWithString:taskId]) {
if (failure) {
failure(@"参数错误", ERROR_CODE);
}
return;
}
NSDictionary *params = @{@"uid": uid,
@"roomId": roomId,
@"channelId": channelId,
@"taskId": taskId,
@"status": @(status)};
[FUSHttpHelper postRequestBinaryWithUrl:FUSShowRoomURLs.fus_URL_interactionGiftTaskComplete params:params success:^(NSDictionary *dataDict, int code) {
if (succeed) {
succeed();
}
} failure:^(NSDictionary *dataDict, int code) {
if (failure) {
NSString *msg = [dataDict[@"msg"] isKindOfClass:NSString.class] ? dataDict[@"msg"] : FAILURE_MESSAGE;
failure(msg, code);
}
}];
}
/// 礼物互动行为-用户获取列表(观众端)
+ (void)fus_requestGiftInteractItemDataListWithUid:(NSString *)uid
roomId:(NSString *)roomId
channelId:(NSString *)channelId
succeed:(void (^)(NSArray *dataList))succeed
failure:(void (^)(NSString *msg, NSInteger code))failure {
if ([NSString isNullWithString:uid] ||
[NSString isNullWithString:roomId] ||
[NSString isNullWithString:channelId]) {
if (failure) {
failure(@"参数错误", ERROR_CODE);
}
return;
}
NSDictionary *params = @{@"uid": uid,
@"roomId": roomId,
@"channelId": channelId};
[FUSHttpHelper postRequestBinaryWithUrl:FUSShowRoomURLs.fus_URL_interactionGiftItemDataList params:params success:^(NSDictionary *dataDict, int code) {
NSArray *list = [dataDict[@"dataList"] isKindOfClass:NSArray.class] ? dataDict[@"dataList"] : @[];
if (succeed) {
succeed(list);
}
} failure:^(NSDictionary *dataDict, int code) {
if (failure) {
failure(FAILURE_MESSAGE, code);
}
}];
}
/** /**
获取包房ip/端口 连接socket 获取包房ip/端口 连接socket
......
...@@ -99,6 +99,7 @@ ...@@ -99,6 +99,7 @@
#import "FUSLivePunishListAlertView.h" #import "FUSLivePunishListAlertView.h"
#import "FUSLivePunishmentManager.h" #import "FUSLivePunishmentManager.h"
#import "FUSLiveGiftInteractTaskPanelView.h" #import "FUSLiveGiftInteractTaskPanelView.h"
#import "FUSLiveGiftInteractAudiencePanelView.h"
#import "FUSLiveGiftInteractSettingItemModel.h" #import "FUSLiveGiftInteractSettingItemModel.h"
// 粒子发射器 cell 重用标识符 // 粒子发射器 cell 重用标识符
...@@ -106,7 +107,6 @@ ...@@ -106,7 +107,6 @@
// segmentView切换通知 // segmentView切换通知
NSString * const kClickCloseBtnNotification = @"kClickCloseBtnNotification"; NSString * const kClickCloseBtnNotification = @"kClickCloseBtnNotification";
static NSString * const FUSGiftInteractSwitchDidChangeNotification = @"FUSGiftInteractSwitchDidChangeNotification";
@interface FUSLiveFunctionView () @interface FUSLiveFunctionView ()
< <
...@@ -227,6 +227,12 @@ BDAlphaPlayerMetalViewDelegate ...@@ -227,6 +227,12 @@ BDAlphaPlayerMetalViewDelegate
@property (nonatomic, strong) NSMutableArray<FUSLiveGiftInteractSettingItemModel *> *giftInteractTaskVisibleList; @property (nonatomic, strong) NSMutableArray<FUSLiveGiftInteractSettingItemModel *> *giftInteractTaskVisibleList;
/// 被点击“消失”的任务集合(本场直播内不再展示) /// 被点击“消失”的任务集合(本场直播内不再展示)
@property (nonatomic, strong) NSMutableSet<NSString *> *giftInteractDismissedTaskIdSet; @property (nonatomic, strong) NSMutableSet<NSString *> *giftInteractDismissedTaskIdSet;
/// 点击“完成”请求中的任务集合(避免重复点击)
@property (nonatomic, strong) NSMutableSet<NSString *> *giftInteractCompletingTaskIdSet;
/// 礼物互动任务面板(观众端,无“消失”,最多展示6条,空态显示“暂无”)
@property (nonatomic, strong) FUSLiveGiftInteractAudiencePanelView *giftInteractAudiencePanelView;
/// 观众端当前展示的任务列表(按 addtime 排序)
@property (nonatomic, strong) NSMutableArray<FUSLiveGiftInteractSettingItemModel *> *giftInteractAudienceVisibleList;
// 标记键盘是否弹起 // 标记键盘是否弹起
@property (nonatomic,assign) BOOL isKeyboard; @property (nonatomic,assign) BOOL isKeyboard;
...@@ -377,6 +383,11 @@ BDAlphaPlayerMetalViewDelegate ...@@ -377,6 +383,11 @@ BDAlphaPlayerMetalViewDelegate
/// PK游戏半屏页面 /// PK游戏半屏页面
@property (nonatomic, strong) FUSHalfWebView *pkGameHalfWebView; @property (nonatomic, strong) FUSHalfWebView *pkGameHalfWebView;
- (void)fus_reuestGameData;
- (void)fus_showWebViewWithUrl:(NSString *)url;
- (FUSHalfWebView *)fus_showHalfWebView:(FUSHalfWebViewModel *)halfWebModel rootView:(UIView *)rootView;
- (CGFloat)fus_chatTextViewHeight;
@end @end
@implementation FUSLiveFunctionView @implementation FUSLiveFunctionView
...@@ -2737,10 +2748,11 @@ BDAlphaPlayerMetalViewDelegate ...@@ -2737,10 +2748,11 @@ BDAlphaPlayerMetalViewDelegate
// 接收主播直播拍一拍用户消息 // 接收主播直播拍一拍用户消息
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(fus_receivePatAudienceUpNotification:) name:STR(ROOM_CID_receivePatAudience) object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(fus_receivePatAudienceUpNotification:) name:STR(ROOM_CID_receivePatAudience) object:nil];
// 监听礼物互动开关状态变化通知 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(fus_receiveGiftInteractSwitchStateDidChangedSocketNotification:) name:STR(ROOM_CID_giftInteractionStateDidChanged) object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(fus_giftInteractSwitchDidChange:) name:FUSGiftInteractSwitchDidChangeNotification object:nil];
// 监听礼物互动任务变化通知 // 监听礼物互动任务变化通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(fus_receiveGiftInteractTaskChangedNotification:) name:STR(ROOM_CID_GIFT_INTERACT_TASK_CHANGED) object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(fus_receiveGiftInteractTaskChangedNotification:) name:STR(ROOM_CID_GIFT_INTERACT_TASK_CHANGED) object:nil];
// 礼物互动任务列表刷新:收到后用 socket dataList 直刷观众端面板,避免等待接口回包
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(fus_receiveGiftInteractAudienceTaskListRefreshSocketNotification:) name:STR(ROOM_CID_GIFT_INTERACT_TASK_LIST_REFRESH) object:nil];
// 接收pk惩罚结束的通知 // 接收pk惩罚结束的通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(fus_livePunishFinishNotification:) name:FUSShowRoomSocket.livePunishFinish object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(fus_livePunishFinishNotification:) name:FUSShowRoomSocket.livePunishFinish object:nil];
...@@ -3342,16 +3354,58 @@ BDAlphaPlayerMetalViewDelegate ...@@ -3342,16 +3354,58 @@ BDAlphaPlayerMetalViewDelegate
} }
#pragma mark - GiftInteract #pragma mark - GiftInteract
/// 礼物互动开关变更通知回调(来源:设置页切换) - (void)fus_receiveGiftInteractSwitchStateDidChangedSocketNotification:(NSNotification *)notification {
- (void)fus_giftInteractSwitchDidChange:(NSNotification *)notification { FUSSocketMessageModel *socketModel = notification.object;
BOOL enabled = [notification.userInfo[@"switchState"] boolValue]; if (![socketModel isKindOfClass:FUSSocketMessageModel.class]) {
[self fus_updateGiftInteractTaskFeatureEnabled:enabled]; return;
if (enabled) {
[self fus_refreshGiftInteractTaskListWithDelay:0.2];
} }
NSDictionary *jsonDict = [socketModel fus_getJsonDict];
if (![jsonDict isKindOfClass:NSDictionary.class]) {
return;
}
NSDictionary *payload = jsonDict[@"data"];
if (![payload isKindOfClass:NSDictionary.class]) {
payload = jsonDict;
}
NSString *userId = [payload[@"userId"] description];
NSString *roomId = [FUSLiveHelper shareInstance].roomInfoModel.roomId ?: @"";
if (roomId.length > 0 && userId.length > 0 && ![roomId isEqualToString:userId]) {
return;
}
BOOL switchState = [payload[@"switchState"] boolValue];
FUSRoomInfoModel *roomInfo = [FUSLiveHelper shareInstance].roomInfoModel;
if (roomInfo && !roomInfo.stateSwitch) {
roomInfo.stateSwitch = [[FUSLiveRoomStateSwitchModel alloc] init];
}
roomInfo.stateSwitch.giftinteractionstate = switchState;
dispatch_async(dispatch_get_main_queue(), ^{
FUSLiveType liveType = [FUSLiveHelper shareInstance].liveType;
if (liveType == FUSLiveTypeAnchor) {
[self fus_updateGiftInteractTaskFeatureEnabled:switchState];
if (switchState) {
[self fus_refreshGiftInteractTaskListWithDelay:0.2];
}
return;
}
if (liveType == FUSLiveTypeAudience) {
[self fus_updateGiftInteractAudienceFeatureEnabled:switchState];
if (switchState) {
[self fus_refreshGiftInteractAudienceListWithDelay:0.2];
}
return;
}
[self fus_updateGiftInteractTaskFeatureEnabled:NO];
[self fus_updateGiftInteractAudienceFeatureEnabled:NO];
});
} }
/// 礼物互动达成变化(收到后主播刷新任务列表) /// 礼物互动达成变化(仅主播端使用:用于触发刷新任务列表)
/// 采用“若面板不存在则尝试创建”的方式,避免 socket 到达时 UI 尚未初始化导致丢刷新
- (void)fus_receiveGiftInteractTaskChangedNotification:(NSNotification *)notification { - (void)fus_receiveGiftInteractTaskChangedNotification:(NSNotification *)notification {
if (!self.giftInteractTaskPanelView) { if (!self.giftInteractTaskPanelView) {
[self fus_updateGiftInteractTaskFeatureEnabled:YES]; [self fus_updateGiftInteractTaskFeatureEnabled:YES];
...@@ -3362,7 +3416,192 @@ BDAlphaPlayerMetalViewDelegate ...@@ -3362,7 +3416,192 @@ BDAlphaPlayerMetalViewDelegate
[self fus_refreshGiftInteractTaskListWithDelay:0.2]; [self fus_refreshGiftInteractTaskListWithDelay:0.2];
} }
/// 礼物互动任务列表刷新(观众端使用:清空并用 socket 下发的 dataList 重新构建)
- (void)fus_receiveGiftInteractAudienceTaskListRefreshSocketNotification:(NSNotification *)notification {
if ([FUSLiveHelper shareInstance].liveType != FUSLiveTypeAudience) {
return;
}
FUSRoomInfoModel *roomInfo = [FUSLiveHelper shareInstance].roomInfoModel;
BOOL enabled = roomInfo.stateSwitch ? roomInfo.stateSwitch.giftinteractionstate : NO;
if (!enabled) {
return;
}
FUSSocketMessageModel *socketModel = notification.object;
if (![socketModel isKindOfClass:FUSSocketMessageModel.class]) {
return;
}
NSString *roomId = roomInfo.roomId ?: @"";
BOOL matchedRoom = YES;
if (socketModel.extend1 > 0) {
matchedRoom = [roomId isEqualToString:[NSString stringWithFormat:@"%d", socketModel.extend1]];
}
NSDictionary *jsonDict = [socketModel fus_getJsonDict];
if (!matchedRoom) {
NSString *socketRoomId = [jsonDict[@"roomId"] description];
matchedRoom = [roomId isEqualToString:socketRoomId];
}
if (!matchedRoom) {
return;
}
NSArray *dataList = jsonDict[@"dataList"];
if (![dataList isKindOfClass:NSArray.class]) {
return;
}
NSMutableArray<FUSLiveGiftInteractSettingItemModel *> *models = [NSMutableArray arrayWithCapacity:dataList.count];
for (NSDictionary *dict in dataList) {
if (![dict isKindOfClass:NSDictionary.class]) {
continue;
}
FUSLiveGiftInteractSettingItemModel *model = [FUSLiveGiftInteractSettingItemModel fus_modelWithDict:dict];
NSString *decodedName = [model.name stringByRemovingPercentEncoding];
if (![NSString isNull:decodedName]) {
model.name = decodedName;
}
[models addObject:model];
}
if (models.count > 6) {
[models removeObjectsInRange:NSMakeRange(6, models.count - 6)];
}
dispatch_async(dispatch_get_main_queue(), ^{
if (!self.giftInteractAudiencePanelView) {
[self fus_updateGiftInteractAudienceFeatureEnabled:YES];
}
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(fus_requestGiftInteractAudienceList) object:nil];
if (!self.giftInteractAudienceVisibleList) {
self.giftInteractAudienceVisibleList = [NSMutableArray array];
}
[self.giftInteractAudienceVisibleList removeAllObjects];
[self.giftInteractAudienceVisibleList addObjectsFromArray:models];
[self fus_reloadGiftInteractAudiencePanel];
});
}
/// 观众端礼物互动面板开关(进房时根据 giftinteractionstate 决定是否展示)
/// 内部兜底校验身份,避免复用场景误创建/误展示
- (void)fus_updateGiftInteractAudienceFeatureEnabled:(BOOL)enabled {
if ([FUSLiveHelper shareInstance].liveType != FUSLiveTypeAudience) {
enabled = NO;
}
if (!enabled) {
[self.giftInteractAudiencePanelView removeFromSuperview];
self.giftInteractAudiencePanelView = nil;
[self.giftInteractAudienceVisibleList removeAllObjects];
return;
}
if (!self.giftInteractAudienceVisibleList) {
self.giftInteractAudienceVisibleList = [NSMutableArray array];
}
[self.giftInteractAudienceVisibleList removeAllObjects];
if (!self.giftInteractAudiencePanelView) {
self.giftInteractAudiencePanelView = [[FUSLiveGiftInteractAudiencePanelView alloc] initWithFrame:CGRectZero];
[[self fus_viewWithLayer:FUSLiveFunctionLayerManualPopView] addSubview:self.giftInteractAudiencePanelView];
}
[self.giftInteractAudiencePanelView fus_updateWithItems:@[]];
[self fus_updateGiftInteractAudiencePanelLayout];
if (self.giftInteractAudienceVisibleList.count == 0) {
[self fus_refreshGiftInteractAudienceListWithDelay:0.2];
}
}
/// 刷新观众端任务列表(通过延迟合并多次触发,避免频繁请求接口)
- (void)fus_refreshGiftInteractAudienceListWithDelay:(NSTimeInterval)delay {
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(fus_requestGiftInteractAudienceList) object:nil];
if (delay <= 0) {
[self fus_requestGiftInteractAudienceList];
} else {
[self performSelector:@selector(fus_requestGiftInteractAudienceList) withObject:nil afterDelay:delay];
}
}
/// 请求观众端任务列表接口并刷新面板(复用任务列表接口,最多展示6条)
- (void)fus_requestGiftInteractAudienceList {
if ([FUSLiveHelper shareInstance].liveType != FUSLiveTypeAudience) {
return;
}
FUSRoomInfoModel *roomInfo = [FUSLiveHelper shareInstance].roomInfoModel;
BOOL enabled = roomInfo.stateSwitch ? roomInfo.stateSwitch.giftinteractionstate : NO;
if (!enabled) {
return;
}
NSString *uid = FUSCacheDataShare.shareStore.userDetailInfo.uid ?: @"";
NSString *roomId = roomInfo.roomId ?: @"";
NSString *channelId = roomInfo.channelId ?: @"";
__weak typeof(self) weakSelf = self;
[FUSLiveHttpHelper fus_requestGiftInteractItemDataListWithUid:uid roomId:roomId channelId:channelId succeed:^(NSArray *dataList) {
NSMutableArray<FUSLiveGiftInteractSettingItemModel *> *models = [NSMutableArray arrayWithCapacity:dataList.count];
for (NSDictionary *dict in dataList) {
if (![dict isKindOfClass:NSDictionary.class]) {
continue;
}
FUSLiveGiftInteractSettingItemModel *model = [FUSLiveGiftInteractSettingItemModel fus_modelWithDict:dict];
NSString *decodedName = [model.name stringByRemovingPercentEncoding];
if (![NSString isNull:decodedName]) {
model.name = decodedName;
}
[models addObject:model];
}
if (models.count > 6) {
[models removeObjectsInRange:NSMakeRange(6, models.count - 6)];
}
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf.giftInteractAudienceVisibleList removeAllObjects];
[weakSelf.giftInteractAudienceVisibleList addObjectsFromArray:models];
[weakSelf fus_reloadGiftInteractAudiencePanel];
});
} failure:^(NSString *msg, NSInteger code) {
}];
}
/// 刷新观众端面板展示(支持礼物图标与数量)
- (void)fus_reloadGiftInteractAudiencePanel {
if (!self.giftInteractAudiencePanelView) {
return;
}
[self.giftInteractAudiencePanelView fus_updateWithItems:self.giftInteractAudienceVisibleList];
[self fus_updateGiftInteractAudiencePanelLayout];
}
/// 计算并刷新观众端面板位置(固定位置,不依赖头部/奖励控件的实时位置)
- (void)fus_updateGiftInteractAudiencePanelLayout {
if (!self.giftInteractAudiencePanelView) {
return;
}
UIView *containerView = [self fus_viewWithLayer:FUSLiveFunctionLayerManualPopView];
CGFloat containerWidth = containerView ? CGRectGetWidth(containerView.bounds) : UIView.fus_screenW;
CGFloat width = 150;
NSInteger count = MIN(6, self.giftInteractAudienceVisibleList.count);
CGFloat height = 0;
CGFloat headerH = 30;
CGFloat padding = 8;
CGFloat rowHeight = 24;
if (count > 0) {
height = headerH + padding * 2 + rowHeight * count;
} else {
height = headerH + 40;
}
CGFloat x = containerWidth - 10 - width;
CGFloat y = UIView.fus_SafeTop + 175;
self.giftInteractAudiencePanelView.frame = CGRectMake(x, y, width, height);
}
/// 开关礼物互动任务展示能力(创建/销毁面板) /// 开关礼物互动任务展示能力(创建/销毁面板)
/// 仅主播端展示;其他身份强制关闭,避免误用导致 UI 异常
- (void)fus_updateGiftInteractTaskFeatureEnabled:(BOOL)enabled { - (void)fus_updateGiftInteractTaskFeatureEnabled:(BOOL)enabled {
if ([FUSLiveHelper shareInstance].liveType != FUSLiveTypeAnchor) { if ([FUSLiveHelper shareInstance].liveType != FUSLiveTypeAnchor) {
enabled = NO; enabled = NO;
...@@ -3378,6 +3617,9 @@ BDAlphaPlayerMetalViewDelegate ...@@ -3378,6 +3617,9 @@ BDAlphaPlayerMetalViewDelegate
if (!self.giftInteractDismissedTaskIdSet) { if (!self.giftInteractDismissedTaskIdSet) {
self.giftInteractDismissedTaskIdSet = [NSMutableSet set]; self.giftInteractDismissedTaskIdSet = [NSMutableSet set];
} }
if (!self.giftInteractCompletingTaskIdSet) {
self.giftInteractCompletingTaskIdSet = [NSMutableSet set];
}
if (!self.giftInteractTaskVisibleList) { if (!self.giftInteractTaskVisibleList) {
self.giftInteractTaskVisibleList = [NSMutableArray array]; self.giftInteractTaskVisibleList = [NSMutableArray array];
} }
...@@ -3398,6 +3640,7 @@ BDAlphaPlayerMetalViewDelegate ...@@ -3398,6 +3640,7 @@ BDAlphaPlayerMetalViewDelegate
} }
/// 刷新任务列表(支持延迟合并多次触发) /// 刷新任务列表(支持延迟合并多次触发)
/// 通过取消上一次请求的延迟调用,合并短时间内的多次触发
- (void)fus_refreshGiftInteractTaskListWithDelay:(NSTimeInterval)delay { - (void)fus_refreshGiftInteractTaskListWithDelay:(NSTimeInterval)delay {
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(fus_requestGiftInteractTaskList) object:nil]; [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(fus_requestGiftInteractTaskList) object:nil];
if (delay <= 0) { if (delay <= 0) {
...@@ -3408,6 +3651,7 @@ BDAlphaPlayerMetalViewDelegate ...@@ -3408,6 +3651,7 @@ BDAlphaPlayerMetalViewDelegate
} }
/// 请求任务列表接口,并更新面板展示(最多6条,按时间排序) /// 请求任务列表接口,并更新面板展示(最多6条,按时间排序)
/// 只保留最小必要校验(身份、开关),其余依赖服务端返回保证数据合法
- (void)fus_requestGiftInteractTaskList { - (void)fus_requestGiftInteractTaskList {
if ([FUSLiveHelper shareInstance].liveType != FUSLiveTypeAnchor) { if ([FUSLiveHelper shareInstance].liveType != FUSLiveTypeAnchor) {
return; return;
...@@ -3434,19 +3678,16 @@ BDAlphaPlayerMetalViewDelegate ...@@ -3434,19 +3678,16 @@ BDAlphaPlayerMetalViewDelegate
if (identity.length && [weakSelf.giftInteractDismissedTaskIdSet containsObject:identity]) { if (identity.length && [weakSelf.giftInteractDismissedTaskIdSet containsObject:identity]) {
continue; continue;
} }
NSString *decodedName = [model.name stringByRemovingPercentEncoding];
if (![NSString isNull:decodedName]) {
model.name = decodedName;
}
[models addObject:model]; [models addObject:model];
} }
[models sortUsingComparator:^NSComparisonResult(FUSLiveGiftInteractSettingItemModel *obj1, FUSLiveGiftInteractSettingItemModel *obj2) {
long long t1 = (long long)[obj1.addtime doubleValue];
long long t2 = (long long)[obj2.addtime doubleValue];
if (t1 != 0 || t2 != 0) {
if (t1 < t2) return NSOrderedAscending;
if (t1 > t2) return NSOrderedDescending;
return NSOrderedSame;
}
return [obj1.addtime compare:obj2.addtime];
}];
if (models.count > 6) { if (models.count > 6) {
[models removeObjectsInRange:NSMakeRange(6, models.count - 6)]; [models removeObjectsInRange:NSMakeRange(6, models.count - 6)];
...@@ -3462,65 +3703,85 @@ BDAlphaPlayerMetalViewDelegate ...@@ -3462,65 +3703,85 @@ BDAlphaPlayerMetalViewDelegate
} }
/// 将模型列表转为面板展示文案并刷新布局 /// 将模型列表转为面板展示文案并刷新布局
/// 文案拼装放在 FunctionView,避免面板 view 依赖业务模型
- (void)fus_reloadGiftInteractTaskPanel { - (void)fus_reloadGiftInteractTaskPanel {
if (!self.giftInteractTaskPanelView) { if (!self.giftInteractTaskPanelView) {
return; return;
} }
NSMutableArray<NSString *> *texts = [NSMutableArray arrayWithCapacity:self.giftInteractTaskVisibleList.count]; [self.giftInteractTaskPanelView fus_updateWithItems:self.giftInteractTaskVisibleList];
for (FUSLiveGiftInteractSettingItemModel *model in self.giftInteractTaskVisibleList) {
NSString *nickname = model.userNickname ?: @"";
NSString *action = model.name ?: @"";
NSString *text = nil;
if (nickname.length > 0) {
text = [NSString stringWithFormat:@"%@:%@", nickname, action];
} else {
text = action;
}
[texts addObject:text ?: @""];
}
[self.giftInteractTaskPanelView fus_updateWithTaskTexts:texts];
[self fus_updateGiftInteractTaskPanelLayout]; [self fus_updateGiftInteractTaskPanelLayout];
} }
/// 计算并刷新任务面板位置(贴近聊天区上方,避免遮挡头部 /// 计算并刷新任务面板位置(固定位置,不依赖头部/奖励控件的实时位置
- (void)fus_updateGiftInteractTaskPanelLayout { - (void)fus_updateGiftInteractTaskPanelLayout {
if (!self.giftInteractTaskPanelView) { if (!self.giftInteractTaskPanelView) {
return; return;
} }
UIView *containerView = [self fus_viewWithLayer:FUSLiveFunctionLayerManualPopView]; UIView *containerView = [self fus_viewWithLayer:FUSLiveFunctionLayerManualPopView];
CGFloat width = 140; CGFloat containerWidth = containerView ? CGRectGetWidth(containerView.bounds) : UIView.fus_screenW;
CGFloat width = 150;
NSInteger count = MIN(6, self.giftInteractTaskVisibleList.count); NSInteger count = MIN(6, self.giftInteractTaskVisibleList.count);
CGFloat height = 110; CGFloat height = 0;
CGFloat headerH = 30;
CGFloat padding = 8;
CGFloat rowHeight = 24;
if (count > 0) { if (count > 0) {
height = 110 + (110.0 / 6.0) * count; height = headerH + padding * 2 + rowHeight * count;
}
CGFloat x = CGRectGetWidth(containerView.bounds) - 15 - width;
CGFloat y = 0;
if (self.anchorRewardView.superview) {
CGRect rewardRect = [containerView convertRect:self.anchorRewardView.frame fromView:self.anchorRewardView.superview];
y = CGRectGetMinY(rewardRect);
} else if (self.pusherPopularView.superview) {
CGRect popRect = [containerView convertRect:self.pusherPopularView.frame fromView:self.pusherPopularView.superview];
y = CGRectGetMaxY(popRect);
} else { } else {
y = 0; height = headerH + 40;
} }
CGFloat x = containerWidth - 10 - width;
CGFloat y = UIView.fus_SafeTop + 175;
self.giftInteractTaskPanelView.frame = CGRectMake(x, y, width, height); self.giftInteractTaskPanelView.frame = CGRectMake(x, y, width, height);
} }
/// 点击“消失”:移除当前任务并加入本场的忽略集合 /// 点击“消失”:移除当前任务并加入本场的忽略集合
/// 仅影响本场展示,不回传服务端
- (void)fus_onGiftInteractTaskDismissAtIndex:(NSInteger)index { - (void)fus_onGiftInteractTaskDismissAtIndex:(NSInteger)index {
if (index < 0 || index >= self.giftInteractTaskVisibleList.count) { if (index < 0 || index >= self.giftInteractTaskVisibleList.count) {
return; return;
} }
FUSLiveGiftInteractSettingItemModel *model = self.giftInteractTaskVisibleList[index]; FUSLiveGiftInteractSettingItemModel *model = self.giftInteractTaskVisibleList[index];
NSString *identity = model.taskId.length ? model.taskId : model.sid; NSString *taskId = model.taskId;
if (identity.length) { if ([NSString isNull:taskId]) {
[self.giftInteractDismissedTaskIdSet addObject:identity]; return;
}
if ([self.giftInteractCompletingTaskIdSet containsObject:taskId]) {
return;
} }
[self.giftInteractTaskVisibleList removeObjectAtIndex:index]; [self.giftInteractCompletingTaskIdSet addObject:taskId];
[self fus_reloadGiftInteractTaskPanel];
FUSRoomInfoModel *roomInfo = [FUSLiveHelper shareInstance].roomInfoModel;
NSString *uid = FUSCacheDataShare.shareStore.userDetailInfo.uid ?: @"";
NSString *roomId = roomInfo.roomId ?: @"";
NSString *channelId = roomInfo.channelId ?: @"";
__weak typeof(self) weakSelf = self;
[FUSLiveHttpHelper fus_requestGiftInteractTaskCompleteWithUid:uid roomId:roomId channelId:channelId taskId:taskId status:1 succeed:^{
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf.giftInteractCompletingTaskIdSet removeObject:taskId];
[weakSelf.giftInteractDismissedTaskIdSet addObject:taskId];
if (index < weakSelf.giftInteractTaskVisibleList.count) {
[weakSelf.giftInteractTaskVisibleList removeObjectAtIndex:index];
} else {
NSUInteger found = [weakSelf.giftInteractTaskVisibleList indexOfObjectPassingTest:^BOOL(FUSLiveGiftInteractSettingItemModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSString *candidate = obj.taskId.length ? obj.taskId : obj.sid;
return [candidate isEqualToString:taskId];
}];
if (found != NSNotFound) {
[weakSelf.giftInteractTaskVisibleList removeObjectAtIndex:found];
}
}
[weakSelf fus_reloadGiftInteractTaskPanel];
});
} failure:^(NSString *msg, NSInteger code) {
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf.giftInteractCompletingTaskIdSet removeObject:taskId];
if (![NSString isNull:msg]) {
[FUSDialogView fus_showDialog:msg];
}
});
}];
} }
/** /**
...@@ -5829,8 +6090,16 @@ BDAlphaPlayerMetalViewDelegate ...@@ -5829,8 +6090,16 @@ BDAlphaPlayerMetalViewDelegate
} }
} }
// 进房时按服务端状态开关决定是否展示,并且仅对当前身份更新对应面板,避免无意义的创建/销毁
BOOL giftInteractEnabled = model.stateSwitch ? model.stateSwitch.giftinteractionstate : NO; BOOL giftInteractEnabled = model.stateSwitch ? model.stateSwitch.giftinteractionstate : NO;
[self fus_updateGiftInteractTaskFeatureEnabled:giftInteractEnabled]; if (FUSSwiftLiveHelper.shared.liveType == FUSLiveTypeAnchor) {
[self fus_updateGiftInteractTaskFeatureEnabled:giftInteractEnabled];
} else if (FUSSwiftLiveHelper.shared.liveType == FUSLiveTypeAudience) {
[self fus_updateGiftInteractAudienceFeatureEnabled:giftInteractEnabled];
} else {
[self fus_updateGiftInteractTaskFeatureEnabled:NO];
[self fus_updateGiftInteractAudienceFeatureEnabled:NO];
}
} }
/** /**
......
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@class FUSLiveGiftInteractSettingItemModel;
@interface FUSLiveGiftInteractAudiencePanelView : UIView
/// 刷新展示条目(支持展示礼物图标与数量)
- (void)fus_updateWithItems:(NSArray<FUSLiveGiftInteractSettingItemModel *> *)items;
@end
NS_ASSUME_NONNULL_END
#import "FUSLiveGiftInteractAudiencePanelView.h"
#import "FUSLiveGiftInteractSettingItemModel.h"
@interface FUSLiveGiftInteractAudiencePanelView ()
/// 顶部标题栏容器
@property (nonatomic, strong) UIView *headerView;
/// 顶部icon
@property (nonatomic, strong) UIImageView *headerIconView;
/// 顶部标题(“互动”)
@property (nonatomic, strong) UILabel *headerTitleLabel;
/// 空态文案(当 texts 为空时显示)
@property (nonatomic, strong) UILabel *emptyLabel;
/// 左侧文本 label 列表(按 texts 数量动态增减)
@property (nonatomic, strong) NSMutableArray<UILabel *> *textLabels;
/// 礼物图标列表(按 items 数量动态增减)
@property (nonatomic, strong) NSMutableArray<UIImageView *> *giftIconViews;
/// 礼物数量 label 列表(按 items 数量动态增减)
@property (nonatomic, strong) NSMutableArray<UILabel *> *giftCountLabels;
/// 当前展示的条目数组
@property (nonatomic, copy) NSArray<FUSLiveGiftInteractSettingItemModel *> *items;
@end
@implementation FUSLiveGiftInteractAudiencePanelView
static NSString *fus_substringComposedToLength(NSString *text, NSUInteger maxLength) {
if (text.length <= maxLength) {
return text;
}
NSRange range = NSMakeRange(0, maxLength);
NSRange safeRange = [text rangeOfComposedCharacterSequencesForRange:range];
return [text substringWithRange:safeRange];
}
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (!self) {
return nil;
}
self.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.35];
self.layer.cornerRadius = 8;
self.clipsToBounds = YES;
self.userInteractionEnabled = YES;
self.headerView = [[UIView alloc] initWithFrame:CGRectZero];
self.headerView.backgroundColor = [UIColor colorWithHex:@"36E6ED" alpha:1];
[self addSubview:self.headerView];
self.headerIconView = [[UIImageView alloc] initWithFrame:CGRectZero];
self.headerIconView.contentMode = UIViewContentModeScaleAspectFit;
self.headerIconView.image = [FUSShowRoomCenterBunble imageNamed:@"Live_bottom_actIcon"];
[self.headerView addSubview:self.headerIconView];
self.headerTitleLabel = [[UILabel alloc] initWithFrame:CGRectZero];
self.headerTitleLabel.text = [NSString fus_localString:@"互动"];
self.headerTitleLabel.font = [UIFont fus_themeFont:15];
self.headerTitleLabel.textColor = UIColor.blackColor;
[self.headerView addSubview:self.headerTitleLabel];
self.textLabels = [NSMutableArray array];
self.giftIconViews = [NSMutableArray array];
self.giftCountLabels = [NSMutableArray array];
self.emptyLabel = [[UILabel alloc] initWithFrame:CGRectZero];
self.emptyLabel.text = [NSString fus_localString:@"暂无"];
self.emptyLabel.textAlignment = NSTextAlignmentCenter;
self.emptyLabel.font = [UIFont fus_themeFont:12];
self.emptyLabel.textColor = UIColor.whiteColor;
[self addSubview:self.emptyLabel];
[self fus_updateWithItems:@[]];
return self;
}
- (void)fus_updateWithItems:(NSArray<FUSLiveGiftInteractSettingItemModel *> *)items {
self.items = items ?: @[];
NSInteger targetCount = self.items.count;
while (self.textLabels.count > targetCount) {
UILabel *label = self.textLabels.lastObject;
[label removeFromSuperview];
[self.textLabels removeLastObject];
}
while (self.giftIconViews.count > targetCount) {
UIImageView *view = self.giftIconViews.lastObject;
[view removeFromSuperview];
[self.giftIconViews removeLastObject];
}
while (self.giftCountLabels.count > targetCount) {
UILabel *label = self.giftCountLabels.lastObject;
[label removeFromSuperview];
[self.giftCountLabels removeLastObject];
}
while (self.textLabels.count < targetCount) {
UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero];
label.font = [UIFont fus_themeFont:12];
label.textColor = UIColor.whiteColor;
label.numberOfLines = 1;
label.lineBreakMode = NSLineBreakByTruncatingTail;
[self addSubview:label];
[self.textLabels addObject:label];
}
while (self.giftIconViews.count < targetCount) {
UIImageView *imgView = [[UIImageView alloc] initWithFrame:CGRectZero];
imgView.contentMode = UIViewContentModeScaleAspectFit;
imgView.clipsToBounds = YES;
[self addSubview:imgView];
[self.giftIconViews addObject:imgView];
}
while (self.giftCountLabels.count < targetCount) {
UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero];
label.font = [UIFont fus_themeFont:11];
label.textColor = UIColor.whiteColor;
label.textAlignment = NSTextAlignmentLeft;
label.numberOfLines = 1;
[self addSubview:label];
[self.giftCountLabels addObject:label];
}
UIImage *placeholder = [FUSShowRoomCenterBunble imageNamed:@"icon_gift_placehold"];
for (NSInteger i = 0; i < targetCount; i++) {
FUSLiveGiftInteractSettingItemModel *model = self.items[i];
NSString *action = model.name ?: @"";
NSString *text = fus_substringComposedToLength(action, 6);
UILabel *textLabel = self.textLabels[i];
textLabel.text = text ?: @"";
UIImageView *giftIconView = self.giftIconViews[i];
NSString *icon = model.giftIcon ?: @"";
if (icon.length == 0) {
giftIconView.image = placeholder;
} else {
NSString *urlString = icon;
if (![urlString containsString:@"http"]) {
urlString = [FUSConfig.sharedInstanced.pathConfigs webImagePath:urlString];
}
NSURL *url = [NSURL URLWithString:urlString];
[giftIconView setImageWithURL:url placeholder:placeholder options:0 completion:nil];
}
UILabel *countLabel = self.giftCountLabels[i];
NSInteger giftNum = model.giftNum;
countLabel.text = (giftNum > 0 ? [NSString stringWithFormat:@"x%ld", (long)giftNum] : @"");
}
self.emptyLabel.hidden = (targetCount > 0);
[self setNeedsLayout];
}
- (void)layoutSubviews {
[super layoutSubviews];
CGFloat headerH = 30;
CGFloat padding = 8;
self.headerView.frame = CGRectMake(0, 0, CGRectGetWidth(self.bounds), headerH);
CGFloat iconSize = 16;
CGFloat spacing = 4;
CGSize titleSize = [self.headerTitleLabel sizeThatFits:CGSizeMake(CGFLOAT_MAX, headerH)];
CGFloat groupW = iconSize + spacing + titleSize.width;
CGFloat groupX = (CGRectGetWidth(self.headerView.bounds) - groupW) * 0.5;
if (groupX < 0) {
groupX = 0;
}
self.headerIconView.frame = CGRectMake(groupX, (headerH - iconSize) * 0.5, iconSize, iconSize);
self.headerTitleLabel.frame = CGRectMake(CGRectGetMaxX(self.headerIconView.frame) + spacing, 0, titleSize.width, headerH);
CGFloat contentTop = CGRectGetMaxY(self.headerView.frame);
if (self.items.count == 0) {
self.emptyLabel.frame = CGRectMake(0, contentTop, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds) - contentTop);
return;
}
self.emptyLabel.frame = CGRectZero;
CGFloat giftIconSize = 18;
CGFloat countW = 28;
CGFloat giftIconX = padding;
CGFloat giftCountX = giftIconX + giftIconSize + 4;
CGFloat labelX = giftCountX + countW + 8;
CGFloat labelW = CGRectGetWidth(self.bounds) - padding - labelX;
if (labelW < 0) {
labelW = 0;
}
CGFloat availableH = CGRectGetHeight(self.bounds) - contentTop - padding * 2;
CGFloat rowHeight = (availableH > 0 ? (availableH / self.items.count) : 0);
for (NSInteger i = 0; i < self.items.count; i++) {
CGFloat y = contentTop + padding + i * rowHeight;
UILabel *label = self.textLabels[i];
label.frame = CGRectMake(labelX, y, labelW, rowHeight);
UIImageView *iconView = self.giftIconViews[i];
iconView.frame = CGRectMake(giftIconX, y + (rowHeight - giftIconSize) * 0.5, giftIconSize, giftIconSize);
UILabel *countLabel = self.giftCountLabels[i];
countLabel.frame = CGRectMake(giftCountX, y, countW, rowHeight);
}
}
@end
...@@ -2,13 +2,15 @@ ...@@ -2,13 +2,15 @@
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
@class FUSLiveGiftInteractSettingItemModel;
@interface FUSLiveGiftInteractTaskPanelView : UIView @interface FUSLiveGiftInteractTaskPanelView : UIView
/// 点击“消失”回调,index 对应 taskTexts 的下标 /// 点击“消失”回调,index 对应 taskTexts 的下标
@property (nonatomic, copy, nullable) void (^doneHandler)(NSInteger index); @property (nonatomic, copy, nullable) void (^doneHandler)(NSInteger index);
/// 刷新展示文本(最多展示调用方传入的数量 /// 刷新展示条目(支持展示头像、昵称与任务文案
- (void)fus_updateWithTaskTexts:(NSArray<NSString *> *)taskTexts; - (void)fus_updateWithItems:(NSArray<FUSLiveGiftInteractSettingItemModel *> *)items;
@end @end
......
#import "FUSLiveGiftInteractTaskPanelView.h" #import "FUSLiveGiftInteractTaskPanelView.h"
#import "FUSLiveGiftInteractSettingItemModel.h"
@interface FUSLiveGiftInteractTaskPanelView () @interface FUSLiveGiftInteractTaskPanelView ()
/// 顶部标题栏 /// 顶部标题栏
...@@ -9,16 +10,29 @@ ...@@ -9,16 +10,29 @@
@property (nonatomic, strong) UILabel *headerTitleLabel; @property (nonatomic, strong) UILabel *headerTitleLabel;
/// 空态文案(当 taskTexts 为空时显示) /// 空态文案(当 taskTexts 为空时显示)
@property (nonatomic, strong) UILabel *emptyLabel; @property (nonatomic, strong) UILabel *emptyLabel;
/// 当前展示的文本数组 /// 当前展示的条目数组
@property (nonatomic, copy) NSArray<NSString *> *taskTexts; @property (nonatomic, copy) NSArray<FUSLiveGiftInteractSettingItemModel *> *items;
/// 左侧文本 label 列表(按 taskTexts 数量动态增减) /// 头像列表(按 items 数量动态增减)
@property (nonatomic, strong) NSMutableArray<UILabel *> *textLabels; @property (nonatomic, strong) NSMutableArray<UIImageView *> *avatarViews;
/// 昵称 label 列表(按 items 数量动态增减)
@property (nonatomic, strong) NSMutableArray<UILabel *> *nicknameLabels;
/// 任务文案 label 列表(按 items 数量动态增减)
@property (nonatomic, strong) NSMutableArray<UILabel *> *taskLabels;
/// 右侧“消失”按钮列表(按 taskTexts 数量动态增减) /// 右侧“消失”按钮列表(按 taskTexts 数量动态增减)
@property (nonatomic, strong) NSMutableArray<UIButton *> *doneButtons; @property (nonatomic, strong) NSMutableArray<UIButton *> *doneButtons;
@end @end
@implementation FUSLiveGiftInteractTaskPanelView @implementation FUSLiveGiftInteractTaskPanelView
static NSString *fus_substringComposedToLength(NSString *text, NSUInteger maxLength) {
if (text.length <= maxLength) {
return text;
}
NSRange range = NSMakeRange(0, maxLength);
NSRange safeRange = [text rangeOfComposedCharacterSequencesForRange:range];
return [text substringWithRange:safeRange];
}
- (instancetype)initWithFrame:(CGRect)frame { - (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame]; self = [super initWithFrame:frame];
if (!self) { if (!self) {
...@@ -44,7 +58,9 @@ ...@@ -44,7 +58,9 @@
self.headerTitleLabel.textColor = UIColor.blackColor; self.headerTitleLabel.textColor = UIColor.blackColor;
[self.headerView addSubview:self.headerTitleLabel]; [self.headerView addSubview:self.headerTitleLabel];
self.textLabels = [NSMutableArray array]; self.avatarViews = [NSMutableArray array];
self.nicknameLabels = [NSMutableArray array];
self.taskLabels = [NSMutableArray array];
self.doneButtons = [NSMutableArray array]; self.doneButtons = [NSMutableArray array];
self.emptyLabel = [[UILabel alloc] initWithFrame:CGRectZero]; self.emptyLabel = [[UILabel alloc] initWithFrame:CGRectZero];
...@@ -54,32 +70,60 @@ ...@@ -54,32 +70,60 @@
self.emptyLabel.textColor = UIColor.whiteColor; self.emptyLabel.textColor = UIColor.whiteColor;
[self addSubview:self.emptyLabel]; [self addSubview:self.emptyLabel];
[self fus_updateWithTaskTexts:@[]]; [self fus_updateWithItems:@[]];
return self; return self;
} }
/// 刷新内容并驱动视图子控件数量与布局更新 - (void)fus_updateWithItems:(NSArray<FUSLiveGiftInteractSettingItemModel *> *)items {
- (void)fus_updateWithTaskTexts:(NSArray<NSString *> *)taskTexts { self.items = items ?: @[];
self.taskTexts = taskTexts ?: @[]; NSInteger targetCount = self.items.count;
NSInteger targetCount = self.taskTexts.count;
while (self.avatarViews.count > targetCount) {
while (self.textLabels.count > targetCount) { UIImageView *view = self.avatarViews.lastObject;
UILabel *label = self.textLabels.lastObject; [view removeFromSuperview];
[self.avatarViews removeLastObject];
}
while (self.nicknameLabels.count > targetCount) {
UILabel *label = self.nicknameLabels.lastObject;
[label removeFromSuperview];
[self.nicknameLabels removeLastObject];
}
while (self.taskLabels.count > targetCount) {
UILabel *label = self.taskLabels.lastObject;
[label removeFromSuperview]; [label removeFromSuperview];
[self.textLabels removeLastObject]; [self.taskLabels removeLastObject];
} }
while (self.doneButtons.count > targetCount) { while (self.doneButtons.count > targetCount) {
UIButton *btn = self.doneButtons.lastObject; UIButton *btn = self.doneButtons.lastObject;
[btn removeFromSuperview]; [btn removeFromSuperview];
[self.doneButtons removeLastObject]; [self.doneButtons removeLastObject];
} }
while (self.textLabels.count < targetCount) { while (self.avatarViews.count < targetCount) {
UIImageView *view = [[UIImageView alloc] initWithFrame:CGRectZero];
view.contentMode = UIViewContentModeScaleAspectFill;
view.clipsToBounds = YES;
[self addSubview:view];
[self.avatarViews addObject:view];
}
while (self.nicknameLabels.count < targetCount) {
UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero]; UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero];
label.font = [UIFont fus_themeFont:12]; label.font = [UIFont fus_themeFont:9];
label.textColor = UIColor.whiteColor; label.textColor = UIColor.whiteColor;
label.numberOfLines = 1; label.numberOfLines = 1;
label.alpha = 0.5;
label.lineBreakMode = NSLineBreakByTruncatingTail;
[self addSubview:label]; [self addSubview:label];
[self.textLabels addObject:label]; [self.nicknameLabels addObject:label];
}
while (self.taskLabels.count < targetCount) {
UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero];
label.font = [UIFont fus_themeFont:10];
label.textColor = UIColor.whiteColor;
label.textAlignment = NSTextAlignmentRight;
label.lineBreakMode = NSLineBreakByTruncatingTail;
[self addSubview:label];
[self.taskLabels addObject:label];
} }
while (self.doneButtons.count < targetCount) { while (self.doneButtons.count < targetCount) {
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom]; UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
...@@ -91,8 +135,23 @@ ...@@ -91,8 +135,23 @@
} }
for (NSInteger i = 0; i < targetCount; i++) { for (NSInteger i = 0; i < targetCount; i++) {
UILabel *label = self.textLabels[i]; FUSLiveGiftInteractSettingItemModel *model = self.items[i];
label.text = self.taskTexts[i] ?: @"";
UIImageView *avatarView = self.avatarViews[i];
avatarView.image = UIImage.fus_defaultIcon;
NSString *face = model.userFace ?: @"";
if (![NSString isNull:face]) {
[avatarView setLiveFaceWebImageWithSubURLString:face placeholder:UIImage.fus_defaultIcon];
}
UILabel *nicknameLabel = self.nicknameLabels[i];
NSString *nickname = model.userNickname ?: @"";
nicknameLabel.text = fus_substringComposedToLength(nickname, 4);
UILabel *taskLabel = self.taskLabels[i];
NSString *task = model.name ?: @"";
taskLabel.text = fus_substringComposedToLength(task, 6);
UIButton *btn = self.doneButtons[i]; UIButton *btn = self.doneButtons[i];
btn.tag = i; btn.tag = i;
} }
...@@ -122,23 +181,39 @@ ...@@ -122,23 +181,39 @@
CGFloat contentTop = CGRectGetMaxY(self.headerView.frame); CGFloat contentTop = CGRectGetMaxY(self.headerView.frame);
if (self.taskTexts.count == 0) { if (self.items.count == 0) {
self.emptyLabel.frame = CGRectMake(0, contentTop, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds) - contentTop); self.emptyLabel.frame = CGRectMake(0, contentTop, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds) - contentTop);
return; return;
} }
self.emptyLabel.frame = CGRectZero; self.emptyLabel.frame = CGRectZero;
CGFloat labelX = padding; CGFloat avatarSize = 18;
CGFloat avatarX = padding;
CGFloat avatarRight = avatarX + avatarSize + 4;
CGFloat nicknameW = 30;
CGFloat nicknameX = avatarRight;
CGFloat taskX = nicknameX + nicknameW + 6;
CGFloat buttonX = CGRectGetWidth(self.bounds) - padding - buttonSize; CGFloat buttonX = CGRectGetWidth(self.bounds) - padding - buttonSize;
CGFloat labelW = buttonX - labelX - 8; CGFloat taskW = buttonX - taskX - 6;
if (taskW < 0) {
taskW = 0;
}
CGFloat availableH = CGRectGetHeight(self.bounds) - contentTop - padding * 2; CGFloat availableH = CGRectGetHeight(self.bounds) - contentTop - padding * 2;
CGFloat rowHeight = (availableH > 0 ? (availableH / self.taskTexts.count) : 0); CGFloat rowHeight = (availableH > 0 ? (availableH / self.items.count) : 0);
for (NSInteger i = 0; i < self.taskTexts.count; i++) { for (NSInteger i = 0; i < self.items.count; i++) {
CGFloat y = contentTop + padding + i * rowHeight; CGFloat y = contentTop + padding + i * rowHeight;
UILabel *label = self.textLabels[i]; UIImageView *avatarView = self.avatarViews[i];
label.frame = CGRectMake(labelX, y, labelW, rowHeight); avatarView.frame = CGRectMake(avatarX, y + (rowHeight - avatarSize) * 0.5, avatarSize, avatarSize);
avatarView.layer.cornerRadius = avatarSize * 0.5;
UILabel *nicknameLabel = self.nicknameLabels[i];
nicknameLabel.frame = CGRectMake(nicknameX, y, nicknameW, rowHeight);
UILabel *taskLabel = self.taskLabels[i];
taskLabel.frame = CGRectMake(taskX, y, taskW, rowHeight);
UIButton *btn = self.doneButtons[i]; UIButton *btn = self.doneButtons[i];
btn.frame = CGRectMake(buttonX, y + (rowHeight - buttonSize) * 0.5, buttonSize, buttonSize); btn.frame = CGRectMake(buttonX, y + (rowHeight - buttonSize) * 0.5, buttonSize, buttonSize);
} }
......
...@@ -38,7 +38,7 @@ class FUSLiveStartContentThemeEditView: UIView { ...@@ -38,7 +38,7 @@ class FUSLiveStartContentThemeEditView: UIView {
let themeSubLabel = UILabel() let themeSubLabel = UILabel()
let closeBtn = UIButton(type: .custom) let closeBtn = UIButton(type: .custom)
let themeSubString = String.fus_localString("设置您的直播主题") let themeSubString = String.fus_localString("设置贴纸文字")
// 初始化data // 初始化data
func setUpData(){ func setUpData(){
......
...@@ -151,7 +151,7 @@ ...@@ -151,7 +151,7 @@
- (void)customInit { - (void)customInit {
self.contentInfoView.lineView.hidden = YES; self.contentInfoView.lineView.hidden = YES;
self.titleLabel.text = [NSString fus_localString:@"设置直播主题"]; self.titleLabel.text = [NSString fus_localString:@"设置贴纸文字"];
self.selectedThemeDescLabel.text = [NSString fus_localString:@"选择模板"]; self.selectedThemeDescLabel.text = [NSString fus_localString:@"选择模板"];
self.themeTitleDescLabel.text = [NSString fus_localString:@"输入主题内容"]; self.themeTitleDescLabel.text = [NSString fus_localString:@"输入主题内容"];
self.themeTitleTextField.placeholder = [NSString fus_localString:@"输入主题内容"]; self.themeTitleTextField.placeholder = [NSString fus_localString:@"输入主题内容"];
......
...@@ -492,6 +492,12 @@ NS_ASSUME_NONNULL_BEGIN ...@@ -492,6 +492,12 @@ NS_ASSUME_NONNULL_BEGIN
/// 礼物互动行为-主播获取任务列表 /// 礼物互动行为-主播获取任务列表
+ (NSString *)fus_URL_interactionGiftTaskList; + (NSString *)fus_URL_interactionGiftTaskList;
/// 礼物互动行为-主播更新任务状态(完成)
+ (NSString *)fus_URL_interactionGiftTaskComplete;
/// 礼物互动行为-用户获取列表(观众端)
+ (NSString *)fus_URL_interactionGiftItemDataList;
/// 礼物互动行为-管理获取配置列表 /// 礼物互动行为-管理获取配置列表
+ (NSString *)fus_URL_interactionGiftManageList; + (NSString *)fus_URL_interactionGiftManageList;
......
...@@ -797,6 +797,16 @@ ...@@ -797,6 +797,16 @@
return [FUSConfig.sharedInstanced.pathConfigs apiUrl:@"/interaction/gift/taskdata/list"]; return [FUSConfig.sharedInstanced.pathConfigs apiUrl:@"/interaction/gift/taskdata/list"];
} }
/// 礼物互动行为-主播更新任务状态(完成)
+ (NSString *)fus_URL_interactionGiftTaskComplete{
return [FUSConfig.sharedInstanced.pathConfigs apiUrl:@"/interaction/gift/taskdata/complete"];
}
/// 礼物互动行为-用户获取列表(观众端)
+ (NSString *)fus_URL_interactionGiftItemDataList{
return [FUSConfig.sharedInstanced.pathConfigs apiUrl:@"/interaction/gift/itemdata/list"];
}
/// 礼物互动行为-管理获取配置列表 /// 礼物互动行为-管理获取配置列表
+ (NSString *)fus_URL_interactionGiftManageList{ + (NSString *)fus_URL_interactionGiftManageList{
return [FUSConfig.sharedInstanced.pathConfigs apiUrl:@"/interaction/gift/manage/list"]; return [FUSConfig.sharedInstanced.pathConfigs apiUrl:@"/interaction/gift/manage/list"];
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment