Commit 91513c4b by suolong

用户进入付费房弹窗

parent 47526a37
.DS_Store .DS_Store
build/
*.xcuserstate *.xcuserstate
*.xcscheme *.xcscheme
FuSiLive.xcodeproj/xcuserdata/fusi.xcuserdatad/xcschemes/xcschememanagement.plist FuSiLive.xcodeproj/xcuserdata/fusi.xcuserdatad/xcschemes/xcschememanagement.plist
......
...@@ -124,69 +124,23 @@ ...@@ -124,69 +124,23 @@
endingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807"
startingLineNumber = "355" startingLineNumber = "355"
endingLineNumber = "355" endingLineNumber = "355"
landmarkName = "FUSLiveStartSetPrivacyView" landmarkName = "fus_requestLiveBeforeReadyIfNeeded(completion:)"
landmarkType = "3">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "B74BD247-B090-42F6-B87A-B0E8C990E91A"
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "Modules/FUSShowRoomModule/FUSShowRoomModule/Features/NewLive/Main/Controller/FUSLiveMainViewController.m"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "741"
endingLineNumber = "741"
landmarkName = "-initPushPrepareView"
landmarkType = "7"> landmarkType = "7">
<Locations>
<Location
uuid = "B74BD247-B090-42F6-B87A-B0E8C990E91A - 1b41df9b0d1316b3"
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
symbolName = "__48-[FUSLiveMainViewController initPushPrepareView]_block_invoke_3"
moduleName = "FuSiLive"
usesParentBreakpointCondition = "Yes"
urlString = "file:///Volumes/MovingDrive/fusi/Modules/FUSShowRoomModule/FUSShowRoomModule/Features/NewLive/Main/Controller/FUSLiveMainViewController.m"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "742"
endingLineNumber = "742">
</Location>
<Location
uuid = "B74BD247-B090-42F6-B87A-B0E8C990E91A - 1b41df9b0d1316fa"
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
symbolName = "__48-[FUSLiveMainViewController initPushPrepareView]_block_invoke_4"
moduleName = "FuSiLive"
usesParentBreakpointCondition = "Yes"
urlString = "file:///Volumes/MovingDrive/fusi/Modules/FUSShowRoomModule/FUSShowRoomModule/Features/NewLive/Main/Controller/FUSLiveMainViewController.m"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "744"
endingLineNumber = "744">
</Location>
</Locations>
</BreakpointContent> </BreakpointContent>
</BreakpointProxy> </BreakpointProxy>
<BreakpointProxy <BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint"> BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent <BreakpointContent
uuid = "F4BE1479-4F1D-4880-9016-00D4F7B4CCA0" uuid = "47DDFACE-B633-4A68-B5D3-CC4B6253CB4F"
shouldBeEnabled = "Yes" shouldBeEnabled = "Yes"
ignoreCount = "0" ignoreCount = "0"
continueAfterRunningActions = "No" continueAfterRunningActions = "No"
filePath = "Modules/FUSShowRoomModule/FUSShowRoomModule/Features/NewLive/Main/View/FunctionView/PayRoom/FUSPayRoomViewerListView.m" filePath = "Modules/FUSShowRoomModule/FUSShowRoomModule/Features/NewLive/Main/Other/FUSLiveHelper.m"
startingColumnNumber = "9223372036854775807" startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807"
startingLineNumber = "94" startingLineNumber = "954"
endingLineNumber = "94" endingLineNumber = "954"
landmarkName = "-fus_loadData" landmarkName = "-joinRoomFailuerWithErrorDict:code:msg:currentRoomId:password:behaviorSrc:otherInfo:"
landmarkType = "7"> landmarkType = "7">
</BreakpointContent> </BreakpointContent>
</BreakpointProxy> </BreakpointProxy>
......
...@@ -1779,6 +1779,10 @@ ...@@ -1779,6 +1779,10 @@
BEEAB2542D3380FA008CD059 /* FusAnchorRewardView.m in Sources */ = {isa = PBXBuildFile; fileRef = BEEAB2522D3380FA008CD059 /* FusAnchorRewardView.m */; }; BEEAB2542D3380FA008CD059 /* FusAnchorRewardView.m in Sources */ = {isa = PBXBuildFile; fileRef = BEEAB2522D3380FA008CD059 /* FusAnchorRewardView.m */; };
00F0A0132F5F0A1B00C0FFEE /* FusAnchorPayRoomView.h in Headers */ = {isa = PBXBuildFile; fileRef = 00F0A0112F5F0A1B00C0FFEE /* FusAnchorPayRoomView.h */; }; 00F0A0132F5F0A1B00C0FFEE /* FusAnchorPayRoomView.h in Headers */ = {isa = PBXBuildFile; fileRef = 00F0A0112F5F0A1B00C0FFEE /* FusAnchorPayRoomView.h */; };
00F0A0142F5F0A1B00C0FFEE /* FusAnchorPayRoomView.m in Sources */ = {isa = PBXBuildFile; fileRef = 00F0A0122F5F0A1B00C0FFEE /* FusAnchorPayRoomView.m */; }; 00F0A0142F5F0A1B00C0FFEE /* FusAnchorPayRoomView.m in Sources */ = {isa = PBXBuildFile; fileRef = 00F0A0122F5F0A1B00C0FFEE /* FusAnchorPayRoomView.m */; };
00F0A1022F9A000100C0FFEE /* FUSPayRoomEntryMainView.h in Headers */ = {isa = PBXBuildFile; fileRef = 00F0A1002F9A000100C0FFEE /* FUSPayRoomEntryMainView.h */; };
00F0A1032F9A000100C0FFEE /* FUSPayRoomEntryMainView.m in Sources */ = {isa = PBXBuildFile; fileRef = 00F0A1012F9A000100C0FFEE /* FUSPayRoomEntryMainView.m */; };
00F0A1122F9A000100C0FFEE /* FUSPayRoomFrostedGlassDataModel.h in Headers */ = {isa = PBXBuildFile; fileRef = 00F0A1102F9A000100C0FFEE /* FUSPayRoomFrostedGlassDataModel.h */; };
00F0A1132F9A000100C0FFEE /* FUSPayRoomFrostedGlassDataModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 00F0A1112F9A000100C0FFEE /* FUSPayRoomFrostedGlassDataModel.m */; };
BEEAB2632D34CC60008CD059 /* FUSLiveStartSetPrivacyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BEEAB2612D34CC60008CD059 /* FUSLiveStartSetPrivacyView.swift */; }; BEEAB2632D34CC60008CD059 /* FUSLiveStartSetPrivacyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BEEAB2612D34CC60008CD059 /* FUSLiveStartSetPrivacyView.swift */; };
A1B2C3D4E5F60718293A4B6C /* FUSPayRoomViewerPopView.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B2C3D4E5F60718293A4B6A /* FUSPayRoomViewerPopView.h */; }; A1B2C3D4E5F60718293A4B6C /* FUSPayRoomViewerPopView.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B2C3D4E5F60718293A4B6A /* FUSPayRoomViewerPopView.h */; };
A1B2C3D4E5F60718293A4B6D /* FUSPayRoomViewerPopView.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C3D4E5F60718293A4B6B /* FUSPayRoomViewerPopView.m */; }; A1B2C3D4E5F60718293A4B6D /* FUSPayRoomViewerPopView.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C3D4E5F60718293A4B6B /* FUSPayRoomViewerPopView.m */; };
...@@ -4140,6 +4144,10 @@ ...@@ -4140,6 +4144,10 @@
BEEAB2522D3380FA008CD059 /* FusAnchorRewardView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FusAnchorRewardView.m; sourceTree = "<group>"; }; BEEAB2522D3380FA008CD059 /* FusAnchorRewardView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FusAnchorRewardView.m; sourceTree = "<group>"; };
00F0A0112F5F0A1B00C0FFEE /* FusAnchorPayRoomView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FusAnchorPayRoomView.h; sourceTree = "<group>"; }; 00F0A0112F5F0A1B00C0FFEE /* FusAnchorPayRoomView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FusAnchorPayRoomView.h; sourceTree = "<group>"; };
00F0A0122F5F0A1B00C0FFEE /* FusAnchorPayRoomView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FusAnchorPayRoomView.m; sourceTree = "<group>"; }; 00F0A0122F5F0A1B00C0FFEE /* FusAnchorPayRoomView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FusAnchorPayRoomView.m; sourceTree = "<group>"; };
00F0A1002F9A000100C0FFEE /* FUSPayRoomEntryMainView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FUSPayRoomEntryMainView.h; sourceTree = "<group>"; };
00F0A1012F9A000100C0FFEE /* FUSPayRoomEntryMainView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FUSPayRoomEntryMainView.m; sourceTree = "<group>"; };
00F0A1102F9A000100C0FFEE /* FUSPayRoomFrostedGlassDataModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FUSPayRoomFrostedGlassDataModel.h; sourceTree = "<group>"; };
00F0A1112F9A000100C0FFEE /* FUSPayRoomFrostedGlassDataModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FUSPayRoomFrostedGlassDataModel.m; sourceTree = "<group>"; };
A1B2C3D4E5F60718293A4B6A /* FUSPayRoomViewerPopView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FUSPayRoomViewerPopView.h; sourceTree = "<group>"; }; A1B2C3D4E5F60718293A4B6A /* FUSPayRoomViewerPopView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FUSPayRoomViewerPopView.h; sourceTree = "<group>"; };
A1B2C3D4E5F60718293A4B6B /* FUSPayRoomViewerPopView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FUSPayRoomViewerPopView.m; sourceTree = "<group>"; }; A1B2C3D4E5F60718293A4B6B /* FUSPayRoomViewerPopView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FUSPayRoomViewerPopView.m; sourceTree = "<group>"; };
A1B2C3D4E5F60718293A4B7C /* FUSPayRoomViewerListView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FUSPayRoomViewerListView.h; sourceTree = "<group>"; }; A1B2C3D4E5F60718293A4B7C /* FUSPayRoomViewerListView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FUSPayRoomViewerListView.h; sourceTree = "<group>"; };
...@@ -7737,9 +7745,21 @@ ...@@ -7737,9 +7745,21 @@
path = AnchorReward; path = AnchorReward;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
00F0A0FE2F9A000100C0FFEE /* EntryMain */ = {
isa = PBXGroup;
children = (
00F0A1002F9A000100C0FFEE /* FUSPayRoomEntryMainView.h */,
00F0A1012F9A000100C0FFEE /* FUSPayRoomEntryMainView.m */,
00F0A1102F9A000100C0FFEE /* FUSPayRoomFrostedGlassDataModel.h */,
00F0A1112F9A000100C0FFEE /* FUSPayRoomFrostedGlassDataModel.m */,
);
path = EntryMain;
sourceTree = "<group>";
};
00F0A0102F5F0A1B00C0FFEE /* PayRoom */ = { 00F0A0102F5F0A1B00C0FFEE /* PayRoom */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
00F0A0FE2F9A000100C0FFEE /* EntryMain */,
00F0A0112F5F0A1B00C0FFEE /* FusAnchorPayRoomView.h */, 00F0A0112F5F0A1B00C0FFEE /* FusAnchorPayRoomView.h */,
00F0A0122F5F0A1B00C0FFEE /* FusAnchorPayRoomView.m */, 00F0A0122F5F0A1B00C0FFEE /* FusAnchorPayRoomView.m */,
A1B2C3D4E5F60718293A4B6A /* FUSPayRoomViewerPopView.h */, A1B2C3D4E5F60718293A4B6A /* FUSPayRoomViewerPopView.h */,
...@@ -8776,6 +8796,8 @@ ...@@ -8776,6 +8796,8 @@
BED658DE2C5B745E00668116 /* FUSAudiencePopView.h in Headers */, BED658DE2C5B745E00668116 /* FUSAudiencePopView.h in Headers */,
BEEAB2532D3380FA008CD059 /* FusAnchorRewardView.h in Headers */, BEEAB2532D3380FA008CD059 /* FusAnchorRewardView.h in Headers */,
00F0A0132F5F0A1B00C0FFEE /* FusAnchorPayRoomView.h in Headers */, 00F0A0132F5F0A1B00C0FFEE /* FusAnchorPayRoomView.h in Headers */,
00F0A1022F9A000100C0FFEE /* FUSPayRoomEntryMainView.h in Headers */,
00F0A1122F9A000100C0FFEE /* FUSPayRoomFrostedGlassDataModel.h in Headers */,
A1B2C3D4E5F60718293A4B6C /* FUSPayRoomViewerPopView.h in Headers */, A1B2C3D4E5F60718293A4B6C /* FUSPayRoomViewerPopView.h in Headers */,
A1B2C3D4E5F60718293A4B8B /* FUSPayRoomViewerListView.h in Headers */, A1B2C3D4E5F60718293A4B8B /* FUSPayRoomViewerListView.h in Headers */,
BED65A572C5B745F00668116 /* FUSLiveTreasureBoxRecordDetailView.h in Headers */, BED65A572C5B745F00668116 /* FUSLiveTreasureBoxRecordDetailView.h in Headers */,
...@@ -10717,6 +10739,8 @@ ...@@ -10717,6 +10739,8 @@
BED65A2E2C5B745F00668116 /* FUSLiveShareHttpHelper.m in Sources */, BED65A2E2C5B745F00668116 /* FUSLiveShareHttpHelper.m in Sources */,
BEEAB2542D3380FA008CD059 /* FusAnchorRewardView.m in Sources */, BEEAB2542D3380FA008CD059 /* FusAnchorRewardView.m in Sources */,
00F0A0142F5F0A1B00C0FFEE /* FusAnchorPayRoomView.m in Sources */, 00F0A0142F5F0A1B00C0FFEE /* FusAnchorPayRoomView.m in Sources */,
00F0A1032F9A000100C0FFEE /* FUSPayRoomEntryMainView.m in Sources */,
00F0A1132F9A000100C0FFEE /* FUSPayRoomFrostedGlassDataModel.m in Sources */,
A1B2C3D4E5F60718293A4B6D /* FUSPayRoomViewerPopView.m in Sources */, A1B2C3D4E5F60718293A4B6D /* FUSPayRoomViewerPopView.m in Sources */,
A1B2C3D4E5F60718293A4B8D /* FUSPayRoomViewerListView.m in Sources */, A1B2C3D4E5F60718293A4B8D /* FUSPayRoomViewerListView.m in Sources */,
BED65ABF2C5B745F00668116 /* FUSHomeNovaListBroadcastHelper.m in Sources */, BED65ABF2C5B745F00668116 /* FUSHomeNovaListBroadcastHelper.m in Sources */,
...@@ -27,6 +27,9 @@ ...@@ -27,6 +27,9 @@
#import "FUSBeautySteakerHelper.h" #import "FUSBeautySteakerHelper.h"
#import "FUSShowRoomModule/FUSShowRoomModule-Swift.h" #import "FUSShowRoomModule/FUSShowRoomModule-Swift.h"
#import "FUSPayRoomEntryMainView.h"
#import "FUSPayRoomFrostedGlassDataModel.h"
#import <FirebaseAnalytics/FirebaseAnalytics.h> #import <FirebaseAnalytics/FirebaseAnalytics.h>
#import "FUSLivePunishmentManager.h" #import "FUSLivePunishmentManager.h"
...@@ -950,6 +953,116 @@ static NSString *const KLiveDataCenter_store_liveRTCData = @"LiveDataCenter_stor ...@@ -950,6 +953,116 @@ static NSString *const KLiveDataCenter_store_liveRTCData = @"LiveDataCenter_stor
[[[FUSLiveHelper shareInstance] liveVC] initLiveEndViewWithInfoDict:errorDict]; [[[FUSLiveHelper shareInstance] liveVC] initLiveEndViewWithInfoDict:errorDict];
[[NSNotificationCenter defaultCenter] postNotificationName:FUSLiveNotificationKeys.fus_BaoFang_Did_End_Live_Notification object:currentRoomId]; [[NSNotificationCenter defaultCenter] postNotificationName:FUSLiveNotificationKeys.fus_BaoFang_Did_End_Live_Notification object:currentRoomId];
[[NSNotificationCenter defaultCenter] postNotificationName:FUSLiveNotificationKeys.fus_BaoFang_Refresh object:nil]; [[NSNotificationCenter defaultCenter] postNotificationName:FUSLiveNotificationKeys.fus_BaoFang_Refresh object:nil];
} else if (code == -20065) {
NSString *uid = [[FUSCacheDataShare shareStore].userVerifyInfo.uid description];
NSString *roomId = [currentRoomId description];
if ([NSString isNull:uid] || [NSString isNull:roomId]) {
[FUSLiveHelper fus_quitLiveWithCompletion:nil];
return;
}
__weak typeof(self) weakSelf = self;
[FUSLiveHttpHelper fus_requestGetPayRoomFrostedGlassDataWithUid:uid RoomId:roomId succeed:^(NSDictionary *dataDict) {
__strong typeof(weakSelf) strongSelf = weakSelf;
if (!strongSelf) {
return;
}
NSDictionary *payload = nil;
if ([dataDict[@"data"] isKindOfClass:NSDictionary.class]) {
payload = dataDict[@"data"];
} else {
payload = dataDict;
}
FUSPayRoomFrostedGlassDataModel *dataModel = [FUSPayRoomFrostedGlassDataModel fus_modelWithDict:(payload ?: @{})];
FUSPayRoomEntryMainViewModel *viewModel = [[FUSPayRoomEntryMainViewModel alloc] init];
NSString *introduce = [dataModel.roomData.introduce description];
NSString *nick = [dataModel.roomData.nickName description];
viewModel.liveTitle = (![NSString isNull:introduce] ? introduce : (nick ?: @""));
NSInteger liveSeconds = dataModel.roomData.liveTime;
if (liveSeconds > 0) {
double hoursValue = ((double)liveSeconds / 3600.0);
NSInteger hours = (NSInteger)llround(hoursValue);
viewModel.liveTotalDurationText = [NSString stringWithFormat:[NSString fus_localString:@"直播总时长:%ld小时"], (long)MAX(0, hours)];
} else {
viewModel.liveTotalDurationText = @"";
}
viewModel.anchorName = nick;
viewModel.anchorFacePath = [dataModel.roomData.face description];
viewModel.anchorLevel = 0;
viewModel.accompanyCount = dataModel.roomData.payViewingNum;
NSMutableArray<NSString *> *facePaths = [NSMutableArray array];
for (FUSOnlineUserModel *user in (dataModel.roomData.payViewingList ?: @[])) {
NSString *face = [user.face description];
if (![NSString isNull:face]) {
[facePaths addObject:face];
}
}
viewModel.accompanyUserFacePaths = facePaths.copy;
NSInteger pricePerMinute = dataModel.payRoomConfigData.payUnitPrice;
NSInteger canCompanionTime = dataModel.userData.canCompanionTime;
NSInteger previewTime = dataModel.payRoomConfigData.previewTime;
BOOL diamondEnough = (dataModel.userData.isDiamondEnough > 0);
if (diamondEnough) {
viewModel.primaryButtonTitle = [NSString fus_localString:@"进入陪伴"];
} else {
viewModel.primaryButtonTitle = [NSString fus_localString:@"马上储值进入陪伴"];
}
viewModel.trialButtonHidden = previewTime <= 0;
if (previewTime > 0) {
viewModel.trialButtonTitle = [NSString stringWithFormat:[NSString fus_localString:@"试看%ldS"], (long)previewTime];
}
if (canCompanionTime > 0 && pricePerMinute > 0) {
viewModel.bottomTipText = [NSString stringWithFormat:[NSString fus_localString:@"您可陪伴%ld分钟,%ld/分钟"], (long)canCompanionTime, (long)pricePerMinute];
} else if (pricePerMinute > 0) {
viewModel.bottomTipText = [NSString stringWithFormat:[NSString fus_localString:@"%ld/分钟"], (long)pricePerMinute];
}
dispatch_async(dispatch_get_main_queue(), ^{
UIView *rootView = strongSelf.liveVC.view ?: [UIViewController fus_topViewController].view;
__block __weak FUSPayRoomEntryMainView *weakEntryView = nil;
FUSPayRoomEntryMainView *entryView = [FUSPayRoomEntryMainView fus_showOnView:rootView viewModel:viewModel actionHandler:^(FUSPayRoomEntryMainViewAction action) {
if (action == FUSPayRoomEntryMainViewActionDismiss) {
[FUSLiveHelper fus_quitLiveWithCompletion:nil];
return;
}
if (action == FUSPayRoomEntryMainViewActionPrimary) {
[weakEntryView fus_dismissAnimated:YES];
if (diamondEnough) {
[strongSelf fus_audienceJoinRoomWithRoomId:roomId password:(password ?: @"") behaviorSrc:behaviorSrc otherInfo:otherInfo];
} else {
[FUSLiveGiftHalfChargeView fus_createWithDismissHandle:^(NSInteger type) {
}];
}
return;
}
if (action == FUSPayRoomEntryMainViewActionTrial) {
[weakEntryView fus_dismissAnimated:YES];
[strongSelf fus_audienceJoinRoomWithRoomId:roomId password:(password ?: @"") behaviorSrc:behaviorSrc otherInfo:otherInfo];
return;
}
}];
weakEntryView = entryView;
});
} failure:^(NSString *msg, NSInteger code) {
__strong typeof(weakSelf) strongSelf = weakSelf;
if (!strongSelf) {
return;
}
dispatch_async(dispatch_get_main_queue(), ^{
[FUSLiveHelper fus_quitLiveWithCompletion:nil];
});
}];
return;
} else if (code == -20060) { } else if (code == -20060) {
[[NSNotificationCenter defaultCenter] postNotificationName:FUSLiveNotificationKeys.fus_BaoFang_Refresh object:nil]; [[NSNotificationCenter defaultCenter] postNotificationName:FUSLiveNotificationKeys.fus_BaoFang_Refresh object:nil];
......
...@@ -1063,6 +1063,15 @@ NS_ASSUME_NONNULL_BEGIN ...@@ -1063,6 +1063,15 @@ NS_ASSUME_NONNULL_BEGIN
roundId:(NSString *)roundId roundId:(NSString *)roundId
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 failure 0
+(void)fus_requestGetPayRoomFrostedGlassDataWithUid:(NSString *)uid
RoomId:(NSString *)roomId
succeed:(void (^)(NSDictionary *dataDict))succeed
failure:(void(^)(NSString *msg,NSInteger code))failure;
/// 切换付费模式V2 /// 切换付费模式V2
/// @param uid 用户ID /// @param uid 用户ID
/// @param fid 主播ID /// @param fid 主播ID
......
...@@ -2975,6 +2975,27 @@ ...@@ -2975,6 +2975,27 @@
if (failure) failure(dataDict[@"msg"],code); if (failure) failure(dataDict[@"msg"],code);
}]; }];
} }
/// 视图-用户端未付费时退出到毛玻璃状态的弹窗数据
/// @param uid 用户ID
/// @param roomId 房间ID
/// @param failure 0
+(void)fus_requestGetPayRoomFrostedGlassDataWithUid:(NSString *)uid
RoomId:(NSString *)roomId
succeed:(void (^)(NSDictionary *dataDict))succeed
failure:(void(^)(NSString *msg,NSInteger code))failure
{
NSDictionary *parm = @{@"uid": uid,
@"roomId":roomId};
[FUSHttpHelper postRequestBinaryWithUrl:FUSShowRoomURLs.fus_URL_liveGetPayRoomFrostedGlassData params:parm success:^(NSDictionary * _Nullable dataDict, int code) {
if (succeed) {
succeed(dataDict);
}
}failure:^(NSDictionary * _Nullable dataDict, int code) {
if (failure) failure(dataDict[@"msg"],code);
}];
}
/// 切换付费模式V2 /// 切换付费模式V2
/// @param uid 用户ID /// @param uid 用户ID
/// @param fid 主播ID /// @param fid 主播ID
......
//
// FUSPayRoomEntryMainView.h
// FUSShowRoomModule
//
// Created by 索隆 on 2026/3/12.
//
// 说明:
// - 付费房观众进入时的主入口卡片(仅包含白色居中窗口内容)。
// - 该组件只负责展示与回调,不内置扣费/试看计时/接口请求等业务逻辑。
//
// 使用方式(示例):
// 1) 构造 ViewModel,填充主播信息、陪伴人数、按钮文案等
// 2) 调用 +fus_showOnView:viewModel:actionHandler: 展示
// 3) 在 actionHandler 中分发业务:关闭/进入陪伴/试看
//
// 备注:
// - 为避免重复叠加弹层,重复调用 show 会复用已存在的同类实例并刷新 UI。
// - 该 ViewModel 为值容器,建议每次更新都重新构造一个新的实例传入,避免多处引用带来状态同步复杂度。
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(NSInteger, FUSPayRoomEntryMainViewAction) {
/// 点击背景/关闭(仅表示用户想关闭,是否真正关闭由外部决定)
FUSPayRoomEntryMainViewActionDismiss = 0,
/// 点击“进入陪伴/马上储值进入陪伴”等主按钮
FUSPayRoomEntryMainViewActionPrimary = 1,
/// 点击“试看xxS”按钮
FUSPayRoomEntryMainViewActionTrial = 2,
};
/// 付费房入口页的展示数据
@interface FUSPayRoomEntryMainViewModel : NSObject
/// 直播标题(为空时建议外部传入默认文案)
@property (nonatomic, copy) NSString *liveTitle;
/// 直播总时长文案(例如:直播总时长:222小时)
@property (nonatomic, copy) NSString *liveTotalDurationText;
/// 主播昵称
@property (nonatomic, copy) NSString *anchorName;
/// 主播头像地址(face path / url)
@property (nonatomic, copy) NSString *anchorFacePath;
/// 主播等级(用于显示富豪挂件;不需要可传 0)
@property (nonatomic, assign) NSInteger anchorLevel;
/// 陪伴人数(用于“xx人在陪伴”)
@property (nonatomic, assign) NSInteger accompanyCount;
/// 陪伴用户头像列表(最多展示 8 个;为空时会展示 1 个默认头像占位)
@property (nonatomic, copy) NSArray<NSString *> *accompanyUserFacePaths;
/// 主按钮标题(例如:进入陪伴 / 马上储值进入陪伴)
@property (nonatomic, copy) NSString *primaryButtonTitle;
/// 试看按钮标题(例如:试看20S)
@property (nonatomic, copy) NSString *trialButtonTitle;
/// 是否隐藏试看按钮(不支持试看、试看已用完等场景)
@property (nonatomic, assign) BOOL trialButtonHidden;
/// 底部提示文案(例如:您可陪伴 XXX 分钟,20/分钟)
@property (nonatomic, copy) NSString *bottomTipText;
/// 点击背景是否触发 dismiss 回调(默认 YES;某些强制付费场景可置为 NO)
@property (nonatomic, assign) BOOL dismissWhenTapBackground;
@end
/// 付费房观众进入的主界面(居中卡片组件)
@interface FUSPayRoomEntryMainView : UIView
/// 当前展示数据(更新后会自动刷新 UI)
@property (nonatomic, strong, readonly) FUSPayRoomEntryMainViewModel *viewModel;
/// 用户交互回调(主按钮/试看/关闭)
@property (nonatomic, copy, nullable) void (^actionHandler)(FUSPayRoomEntryMainViewAction action);
/// 在指定父视图上显示(默认带渐入动画)
+ (instancetype)fus_showOnView:(UIView *)rootView
viewModel:(FUSPayRoomEntryMainViewModel *)viewModel
actionHandler:(void (^ _Nullable)(FUSPayRoomEntryMainViewAction action))actionHandler;
/// 更新展示数据
- (void)fus_updateWithViewModel:(FUSPayRoomEntryMainViewModel *)viewModel;
/// 关闭并移除(默认带渐隐动画)
- (void)fus_dismissAnimated:(BOOL)animated;
@end
NS_ASSUME_NONNULL_END
//
// FUSPayRoomEntryMainView.m
// FUSShowRoomModule
//
// Created by 索隆 on 2026/3/12.
//
// 设计目标:
// - 作为“用户进入付费房”的入口主界面(仅居中的白色卡片窗口),用于承载用户决策:进入陪伴/马上储值进入陪伴/试看。
// - 视图只负责展示与交互分发,不直接发起网络请求/扣费逻辑,避免耦合业务与 UI 生命周期。
// - 外部通过 ViewModel 统一驱动 UI,便于在多处场景复用(首次进入、试看后再进入、余额不足提示等)。
//
// 线程与生命周期说明:
// - UI 更新要求在主线程执行;本类不做线程切换,调用方需保证。
// - 该 View 通过 +fus_showOnView:... 方式复用同类实例,防止重复叠加遮罩导致触摸穿透/层级错乱。
//
#import "FUSPayRoomEntryMainView.h"
#import <Masonry/Masonry.h>
#import <FUSFoundation/FUSFoundation.h>
#import <FUSCommon/FUSCommon.h>
@implementation FUSPayRoomEntryMainViewModel
- (instancetype)init {
self = [super init];
if (self) {
_liveTitle = @"";
_liveTotalDurationText = @"";
_anchorName = @"";
_anchorFacePath = @"";
_anchorLevel = 0;
_accompanyCount = 0;
_accompanyUserFacePaths = @[];
_primaryButtonTitle = [NSString fus_localString:@"进入陪伴"];
_trialButtonTitle = [NSString fus_localString:@"试看20S"];
_trialButtonHidden = NO;
_bottomTipText = @"";
_dismissWhenTapBackground = YES;
}
return self;
}
@end
@interface FUSPayRoomEntryMainView ()
@property (nonatomic, strong) UIButton *backgroundButton;
@property (nonatomic, strong) UIView *cardView;
@property (nonatomic, strong) UIView *titleBarView;
@property (nonatomic, strong) UILabel *titleLabel;
@property (nonatomic, strong) UILabel *durationLabel;
@property (nonatomic, strong) FUSRichIconView *anchorAvatarView;
@property (nonatomic, strong) UILabel *anchorNameLabel;
@property (nonatomic, strong) UIView *accompanyAvatarContainerView;
@property (nonatomic, strong) NSMutableArray<UIImageView *> *accompanyAvatarViews;
@property (nonatomic, strong) UILabel *accompanyCountLabel;
@property (nonatomic, strong) UIButton *primaryButton;
@property (nonatomic, strong) UIButton *trialButton;
@property (nonatomic, strong) UIView *trialButtonDividerView;
@property (nonatomic, strong) UILabel *bottomTipLabel;
@property (nonatomic, strong) FUSPayRoomEntryMainViewModel *viewModel;
@property (nonatomic, strong) MASConstraint *trialButtonHeightConstraint;
@property (nonatomic, strong) MASConstraint *trialButtonTopConstraint;
@property (nonatomic, strong) MASConstraint *trialButtonDividerHeightConstraint;
@property (nonatomic, strong) MASConstraint *accompanyAvatarContainerWidthConstraint;
@end
@implementation FUSPayRoomEntryMainView
+ (instancetype)fus_showOnView:(UIView *)rootView
viewModel:(FUSPayRoomEntryMainViewModel *)viewModel
actionHandler:(void (^ _Nullable)(FUSPayRoomEntryMainViewAction action))actionHandler {
if (!rootView) {
return nil;
}
for (UIView *subview in rootView.subviews) {
if ([subview isKindOfClass:[FUSPayRoomEntryMainView class]]) {
FUSPayRoomEntryMainView *existView = (FUSPayRoomEntryMainView *)subview;
[rootView bringSubviewToFront:existView];
existView.actionHandler = actionHandler;
[existView mas_remakeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(rootView);
}];
[existView fus_updateWithViewModel:viewModel];
[existView fus_showAnimated:YES];
return existView;
}
}
FUSPayRoomEntryMainView *view = [[FUSPayRoomEntryMainView alloc] initWithFrame:rootView.bounds];
view.actionHandler = actionHandler;
[rootView addSubview:view];
[view mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(rootView);
}];
[view fus_updateWithViewModel:viewModel];
[view fus_showAnimated:YES];
return view;
}
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
_accompanyAvatarViews = [[NSMutableArray alloc] init];
[self fus_buildUI];
[self fus_bindActions];
}
return self;
}
- (void)dealloc {
[NSObject cancelPreviousPerformRequestsWithTarget:self];
}
#pragma mark - Public
- (void)fus_updateWithViewModel:(FUSPayRoomEntryMainViewModel *)viewModel {
if (!viewModel) {
viewModel = [[FUSPayRoomEntryMainViewModel alloc] init];
}
self.viewModel = viewModel;
self.titleLabel.text = viewModel.liveTitle;
self.durationLabel.text = viewModel.liveTotalDurationText;
self.anchorNameLabel.text = viewModel.anchorName;
[self.anchorAvatarView fus_setupLiveIconWithFacePath:viewModel.anchorFacePath level:viewModel.anchorLevel animated:NO];
self.accompanyCountLabel.text = [NSString stringWithFormat:[NSString fus_localString:@"%zd人在陪伴"], MAX(0, viewModel.accompanyCount)];
NSString *primaryTitle = ([NSString isNull:viewModel.primaryButtonTitle] ? [NSString fus_localString:@"进入陪伴"] : viewModel.primaryButtonTitle);
[self.primaryButton setTitle:primaryTitle forState:UIControlStateNormal];
NSString *trialTitle = ([NSString isNull:viewModel.trialButtonTitle] ? [NSString fus_localString:@"试看20S"] : viewModel.trialButtonTitle);
[self.trialButton setTitle:trialTitle forState:UIControlStateNormal];
[self fus_updateBottomTipWithText:viewModel.bottomTipText];
[self fus_updateTrialButtonHidden:viewModel.trialButtonHidden];
[self fus_updateAccompanyAvatarsWithFacePaths:viewModel.accompanyUserFacePaths];
}
- (void)fus_dismissAnimated:(BOOL)animated {
if (!self.superview) {
return;
}
if (!animated) {
[self removeFromSuperview];
return;
}
__weak typeof(self) weakSelf = self;
[UIView animateWithDuration:0.25 animations:^{
weakSelf.alpha = 0;
weakSelf.cardView.transform = CGAffineTransformMakeScale(0.98, 0.98);
} completion:^(BOOL finished) {
[weakSelf removeFromSuperview];
}];
}
#pragma mark - Private: UI
- (void)fus_buildUI {
self.alpha = 0;
self.backgroundColor = UIColor.clearColor;
self.backgroundButton = [UIButton buttonWithType:UIButtonTypeCustom];
self.backgroundButton.backgroundColor = UIColor.clearColor;
[self addSubview:self.backgroundButton];
// 卡片层:承载内容与操作按钮。
self.cardView = [[UIView alloc] initWithFrame:CGRectZero];
self.cardView.backgroundColor = UIColor.whiteColor;
self.cardView.layer.cornerRadius = 16;
self.cardView.layer.masksToBounds = YES;
[self addSubview:self.cardView];
self.titleBarView = [[UIView alloc] initWithFrame:CGRectZero];
self.titleBarView.backgroundColor = [UIColor colorWithHex:@"#F5F5F5"];
[self.cardView addSubview:self.titleBarView];
self.titleLabel = [[UILabel alloc] initWithFrame:CGRectZero];
self.titleLabel.font = [UIFont fus_themeMediumFont:18];
self.titleLabel.textColor = [UIColor colorWithHex:@"#2A2A2A"];
self.titleLabel.textAlignment = NSTextAlignmentCenter;
self.titleLabel.numberOfLines = 1;
[self.titleBarView addSubview:self.titleLabel];
self.durationLabel = [[UILabel alloc] initWithFrame:CGRectZero];
self.durationLabel.font = [UIFont fus_themeFont:12];
self.durationLabel.textColor = [UIColor colorWithHex:@"#9B9B9B"];
self.durationLabel.textAlignment = NSTextAlignmentRight;
self.durationLabel.numberOfLines = 1;
[self.cardView addSubview:self.durationLabel];
self.anchorAvatarView = [[FUSRichIconView alloc] initWithFrame:CGRectZero];
self.anchorAvatarView.showNoVipLevel = NO;
self.anchorAvatarView.faceImageView.layer.cornerRadius = 36;
self.anchorAvatarView.faceImageView.layer.masksToBounds = YES;
self.anchorAvatarView.faceImageView.contentMode = UIViewContentModeScaleAspectFill;
[self.cardView addSubview:self.anchorAvatarView];
self.anchorNameLabel = [[UILabel alloc] initWithFrame:CGRectZero];
self.anchorNameLabel.font = [UIFont fus_themeMediumFont:16];
self.anchorNameLabel.textColor = [UIColor colorWithHex:@"#2A2A2A"];
self.anchorNameLabel.textAlignment = NSTextAlignmentCenter;
self.anchorNameLabel.numberOfLines = 1;
[self.cardView addSubview:self.anchorNameLabel];
self.accompanyAvatarContainerView = [[UIView alloc] initWithFrame:CGRectZero];
self.accompanyAvatarContainerView.backgroundColor = UIColor.clearColor;
[self.cardView addSubview:self.accompanyAvatarContainerView];
self.accompanyCountLabel = [[UILabel alloc] initWithFrame:CGRectZero];
self.accompanyCountLabel.font = [UIFont fus_themeFont:12];
self.accompanyCountLabel.textColor = [UIColor colorWithHex:@"#9B9B9B"];
self.accompanyCountLabel.textAlignment = NSTextAlignmentCenter;
[self.cardView addSubview:self.accompanyCountLabel];
self.primaryButton = [UIButton buttonWithType:UIButtonTypeCustom];
self.primaryButton.titleLabel.font = [UIFont fus_themeMediumFont:15];
[self.primaryButton setTitleColor:[UIColor colorWithHex:@"#003333"] forState:UIControlStateNormal];
self.primaryButton.backgroundColor = [UIColor colorWithRed:(45.0 / 255.0) green:(226.0 / 255.0) blue:(224.0 / 255.0) alpha:1.0];
self.primaryButton.layer.cornerRadius = 22;
self.primaryButton.layer.masksToBounds = YES;
[self.cardView addSubview:self.primaryButton];
self.trialButton = [UIButton buttonWithType:UIButtonTypeCustom];
self.trialButton.titleLabel.font = [UIFont fus_themeFont:13];
[self.trialButton setTitleColor:[UIColor colorWithHex:@"#2A2A2A"] forState:UIControlStateNormal];
[self.trialButton setTitleColor:[UIColor colorWithHex:@"#9B9B9B"] forState:UIControlStateDisabled];
[self.cardView addSubview:self.trialButton];
self.trialButtonDividerView = [[UIView alloc] initWithFrame:CGRectZero];
self.trialButtonDividerView.backgroundColor = [UIColor colorWithHex:@"#2A2A2A"];
[self.cardView addSubview:self.trialButtonDividerView];
self.bottomTipLabel = [[UILabel alloc] initWithFrame:CGRectZero];
self.bottomTipLabel.font = [UIFont fus_themeFont:11];
self.bottomTipLabel.textColor = [UIColor colorWithHex:@"#9B9B9B"];
self.bottomTipLabel.textAlignment = NSTextAlignmentCenter;
self.bottomTipLabel.numberOfLines = 2;
[self.cardView addSubview:self.bottomTipLabel];
[self.backgroundButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self);
}];
[self.cardView mas_makeConstraints:^(MASConstraintMaker *make) {
make.center.equalTo(self);
make.size.mas_equalTo(CGSizeMake(285, 366));
}];
[self.titleBarView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.left.right.equalTo(self.cardView);
make.height.mas_equalTo(50);
}];
[self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.equalTo(self.titleBarView);
make.left.equalTo(self.titleBarView).offset(20);
make.right.equalTo(self.titleBarView).offset(-20);
}];
[self.durationLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.titleBarView.mas_bottom).offset(10);
make.left.equalTo(self.cardView).offset(20);
make.right.equalTo(self.cardView).offset(-20);
}];
[self.anchorAvatarView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.durationLabel.mas_bottom).offset(16);
make.centerX.equalTo(self.cardView);
make.size.mas_equalTo(CGSizeMake(72, 72));
}];
[self.anchorNameLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.anchorAvatarView.mas_bottom).offset(12);
make.left.equalTo(self.cardView).offset(20);
make.right.equalTo(self.cardView).offset(-20);
}];
[self.accompanyAvatarContainerView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.anchorNameLabel.mas_bottom).offset(12);
make.centerX.equalTo(self.cardView);
make.height.mas_equalTo(18);
self.accompanyAvatarContainerWidthConstraint = make.width.mas_equalTo(18);
}];
[self.accompanyCountLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.accompanyAvatarContainerView.mas_bottom).offset(10);
make.left.equalTo(self.cardView).offset(20);
make.right.equalTo(self.cardView).offset(-20);
make.height.mas_equalTo(17);
}];
[self.primaryButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.accompanyCountLabel.mas_bottom).offset(14);
make.left.equalTo(self.cardView).offset(20);
make.right.equalTo(self.cardView).offset(-20);
make.height.mas_equalTo(44);
}];
[self.trialButton mas_makeConstraints:^(MASConstraintMaker *make) {
self.trialButtonTopConstraint = make.top.equalTo(self.primaryButton.mas_bottom).offset(10);
make.centerX.equalTo(self.cardView);
self.trialButtonHeightConstraint = make.height.mas_equalTo(20);
}];
[self.trialButtonDividerView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.trialButton.mas_bottom).offset(5);
make.centerX.equalTo(self.cardView);
make.width.mas_equalTo(40);
self.trialButtonDividerHeightConstraint = make.height.mas_equalTo(1);
}];
[self.bottomTipLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.trialButton.mas_bottom).offset(10);
make.left.equalTo(self.cardView).offset(20);
make.right.equalTo(self.cardView).offset(-20);
make.bottom.equalTo(self.cardView).offset(-18);
}];
}
- (void)fus_bindActions {
[self.backgroundButton addTarget:self action:@selector(fus_onTapBackground) forControlEvents:UIControlEventTouchUpInside];
[self.primaryButton addTarget:self action:@selector(fus_onTapPrimary) forControlEvents:UIControlEventTouchUpInside];
[self.trialButton addTarget:self action:@selector(fus_onTapTrial) forControlEvents:UIControlEventTouchUpInside];
}
- (void)fus_showAnimated:(BOOL)animated {
if (!animated) {
self.alpha = 1;
self.cardView.transform = CGAffineTransformIdentity;
return;
}
self.alpha = 0;
self.cardView.transform = CGAffineTransformMakeScale(1.02, 1.02);
__weak typeof(self) weakSelf = self;
[UIView animateWithDuration:0.25 animations:^{
weakSelf.alpha = 1;
weakSelf.cardView.transform = CGAffineTransformIdentity;
}];
}
#pragma mark - Private: Data -> UI
- (void)fus_updateTrialButtonHidden:(BOOL)hidden {
self.trialButton.hidden = hidden;
self.trialButton.userInteractionEnabled = !hidden;
[self.trialButtonHeightConstraint setOffset:(hidden ? 0 : 20)];
[self.trialButtonTopConstraint setOffset:(hidden ? 0 : 10)];
self.trialButtonDividerView.hidden = hidden;
[self.trialButtonDividerHeightConstraint setOffset:(hidden ? 0 : 1)];
[self setNeedsUpdateConstraints];
[self layoutIfNeeded];
}
- (void)fus_updateBottomTipWithText:(NSString *)bottomTipText {
NSString *safeText = ([NSString isNull:bottomTipText] ? @"" : bottomTipText);
if (safeText.length == 0) {
self.bottomTipLabel.attributedText = nil;
self.bottomTipLabel.text = @"";
return;
}
UIImage *jewelIcon = [FUSShowRoomCenterBunble imageNamed:@"video_chat_userinfo_jewel"];
if (!jewelIcon) {
self.bottomTipLabel.attributedText = nil;
self.bottomTipLabel.text = safeText;
return;
}
UIColor *normalTextColor = [UIColor colorWithHex:@"#9B9B9B"];
UIColor *jewelTextColor = UIColor.fus_diamondBlue;
NSTextAttachment *attachment = [[NSTextAttachment alloc] init];
attachment.image = jewelIcon;
attachment.bounds = CGRectMake(0, -2, 12, 12);
NSMutableAttributedString *textAttr = [[NSMutableAttributedString alloc] initWithString:safeText attributes:@{
NSFontAttributeName: self.bottomTipLabel.font,
NSForegroundColorAttributeName: normalTextColor
}];
NSError *regexError = nil;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"(\\d+)\\/分钟" options:0 error:&regexError];
NSArray<NSTextCheckingResult *> *matches = (regexError ? @[] : [regex matchesInString:safeText options:0 range:NSMakeRange(0, safeText.length)]);
NSTextCheckingResult *lastMatch = matches.lastObject;
if (lastMatch && lastMatch.numberOfRanges > 1) {
NSRange digitRange = [lastMatch rangeAtIndex:1];
if (digitRange.location != NSNotFound && NSMaxRange(digitRange) <= safeText.length) {
NSAttributedString *attachmentAttr = [NSAttributedString attributedStringWithAttachment:attachment];
NSAttributedString *spaceAttr = [[NSAttributedString alloc] initWithString:@" " attributes:@{
NSFontAttributeName: self.bottomTipLabel.font,
NSForegroundColorAttributeName: normalTextColor
}];
[textAttr insertAttributedString:attachmentAttr atIndex:digitRange.location];
[textAttr insertAttributedString:spaceAttr atIndex:(digitRange.location + 1)];
[textAttr addAttribute:NSForegroundColorAttributeName value:jewelTextColor range:NSMakeRange(digitRange.location + 2, digitRange.length)];
}
}
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.alignment = NSTextAlignmentCenter;
[textAttr addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, textAttr.length)];
self.bottomTipLabel.attributedText = textAttr;
}
- (void)fus_updateAccompanyAvatarsWithFacePaths:(NSArray<NSString *> *)facePaths {
NSArray<NSString *> *safeFacePaths = (facePaths ?: @[]);
NSUInteger maxCount = 8;
NSUInteger displayCount = MIN(maxCount, safeFacePaths.count);
if (displayCount == 0) {
displayCount = 1;
}
while (self.accompanyAvatarViews.count < displayCount) {
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectZero];
imageView.contentMode = UIViewContentModeScaleAspectFill;
imageView.layer.cornerRadius = 9;
imageView.layer.masksToBounds = YES;
imageView.backgroundColor = [UIColor colorWithHex:@"#E6E6E6"];
[self.accompanyAvatarContainerView addSubview:imageView];
[self.accompanyAvatarViews addObject:imageView];
}
for (NSUInteger idx = 0; idx < self.accompanyAvatarViews.count; idx++) {
UIImageView *imageView = self.accompanyAvatarViews[idx];
BOOL shouldShow = (idx < displayCount);
imageView.hidden = !shouldShow;
if (!shouldShow) {
continue;
}
// 头像加载策略:
// - 外部传入 facePath 为空:使用默认占位图,避免出现空白圆点导致用户误解为“没有人陪伴”。
// - facePath 非空:走直播间头像加载通道(通常带缓存与裁剪策略)。
NSString *facePath = (idx < safeFacePaths.count ? safeFacePaths[idx] : @"");
if ([NSString isNull:facePath]) {
imageView.image = UIImage.fus_defaultIcon;
} else {
[imageView setLiveFaceWebImageWithSubURLString:facePath placeholder:UIImage.fus_defaultIcon];
}
}
CGFloat size = 18;
CGFloat space = 6;
CGFloat totalW = displayCount * size + (displayCount > 0 ? (displayCount - 1) * space : 0);
[self.accompanyAvatarContainerWidthConstraint setOffset:totalW];
for (NSUInteger idx = 0; idx < displayCount; idx++) {
UIImageView *imageView = self.accompanyAvatarViews[idx];
[imageView mas_remakeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.accompanyAvatarContainerView).offset(idx * (size + space));
make.centerY.equalTo(self.accompanyAvatarContainerView);
make.size.mas_equalTo(CGSizeMake(size, size));
}];
}
[self setNeedsUpdateConstraints];
[self layoutIfNeeded];
}
#pragma mark - Actions
- (void)fus_onTapBackground {
if (!self.viewModel.dismissWhenTapBackground) {
return;
}
if (self.actionHandler) {
self.actionHandler(FUSPayRoomEntryMainViewActionDismiss);
}
[self fus_dismissAnimated:YES];
}
- (void)fus_onTapPrimary {
if (self.actionHandler) {
self.actionHandler(FUSPayRoomEntryMainViewActionPrimary);
}
}
- (void)fus_onTapTrial {
if (self.actionHandler) {
self.actionHandler(FUSPayRoomEntryMainViewActionTrial);
}
}
@end
#import <Foundation/Foundation.h>
#import <FUSFoundation/FUSFoundation.h>
#import "FUSOnlineUserModel.h"
/// 主播数据(roomData)
/// 说明:该模型字段严格对应接口字段,不做别名映射与额外推导
@interface FUSPayRoomFrostedGlassRoomDataModel : FUSBaseModel
/// 主播ID(字符串形式)
@property (nonatomic, copy) NSString *roomId;
/// 历史直播时长-当前,单位:秒
@property (nonatomic, assign) NSInteger liveTime;
/// 主播昵称
@property (nonatomic, copy) NSString *nickName;
/// 主播头像地址
@property (nonatomic, copy) NSString *face;
/// 主播直播简介
@property (nonatomic, copy) NSString *introduce;
/// 当前正在陪伴的人数
@property (nonatomic, assign) NSInteger payViewingNum;
/// 陪伴列表(复用已有 FUSOnlineUserModel)
@property (nonatomic, copy) NSArray<FUSOnlineUserModel *> *payViewingList;
/// 直播频道ID
@property (nonatomic, copy) NSString *channelId;
/// 付费房回合ID
@property (nonatomic, copy) NSString *roundId;
@end
/// 用户数据(userData)
/// 说明:仅包含接口定义的字段,不添加推导/冗余数据
@interface FUSPayRoomFrostedGlassUserDataModel : FUSBaseModel
/// 可继续陪伴的时间,单位:分钟
@property (nonatomic, assign) NSInteger canCompanionTime;
/// 用户宝石数是否允许进入陪伴:0 否 1 是
@property (nonatomic, assign) NSInteger isDiamondEnough;
@end
/// 付费房配置(payRoomConfigData)
/// 说明:字段单位与业务语义与接口保持一致
@interface FUSPayRoomFrostedGlassConfigDataModel : FUSBaseModel
/// 付费房允许试看时间,单位:秒
@property (nonatomic, assign) NSInteger previewTime;
/// 付费房单价(宝石)/分钟
@property (nonatomic, assign) NSInteger payUnitPrice;
/// 每次计费时长,单位:分钟
@property (nonatomic, assign) NSInteger billingTime;
/// 历史直播时长-目标,单位:秒
@property (nonatomic, assign) NSInteger liveTimeTarget;
@end
/// 毛玻璃弹窗数据根对象
/// 说明:仅做字段承载与解析,不包含任何计算与兼容映射
@interface FUSPayRoomFrostedGlassDataModel : FUSBaseModel
/// 主播数据
@property (nonatomic, strong) FUSPayRoomFrostedGlassRoomDataModel *roomData;
/// 用户数据
@property (nonatomic, strong) FUSPayRoomFrostedGlassUserDataModel *userData;
/// 付费房配置数据
@property (nonatomic, strong) FUSPayRoomFrostedGlassConfigDataModel *payRoomConfigData;
@end
#import "FUSPayRoomFrostedGlassDataModel.h"
@implementation FUSPayRoomFrostedGlassRoomDataModel
+ (NSDictionary *)modelContainerPropertyGenericClass {
return @{
@"payViewingList": [FUSOnlineUserModel class]
};
}
@end
@implementation FUSPayRoomFrostedGlassUserDataModel
@end
@implementation FUSPayRoomFrostedGlassConfigDataModel
@end
@implementation FUSPayRoomFrostedGlassDataModel
+ (NSDictionary *)modelContainerPropertyGenericClass {
return @{
@"roomData": [FUSPayRoomFrostedGlassRoomDataModel class],
@"userData": [FUSPayRoomFrostedGlassUserDataModel class],
@"payRoomConfigData": [FUSPayRoomFrostedGlassConfigDataModel class]
};
}
@end
...@@ -543,6 +543,8 @@ NS_ASSUME_NONNULL_BEGIN ...@@ -543,6 +543,8 @@ NS_ASSUME_NONNULL_BEGIN
+ (NSString *)fus_URL_vsHostdataRewardBatchGet; + (NSString *)fus_URL_vsHostdataRewardBatchGet;
/// 主播获取左侧小窗付费房信息 /// 主播获取左侧小窗付费房信息
+ (NSString *)fus_URL_liveGetPayRoomData; + (NSString *)fus_URL_liveGetPayRoomData;
/// 视图-用户端未付费时退出到毛玻璃状态的弹窗数据
+ (NSString *)fus_URL_liveGetPayRoomFrostedGlassData;
/// 获取首页自动跳转直播间 /// 获取首页自动跳转直播间
+ (NSString *)fus_URL_indexGetSuccessRecommendResult; + (NSString *)fus_URL_indexGetSuccessRecommendResult;
/// 切换付费模式V2 /// 切换付费模式V2
......
...@@ -886,6 +886,11 @@ ...@@ -886,6 +886,11 @@
{ {
return [FUSConfig.sharedInstanced.pathConfigs apiUrl:@"/payRoom/getPayRoomData"]; return [FUSConfig.sharedInstanced.pathConfigs apiUrl:@"/payRoom/getPayRoomData"];
} }
/// 视图-用户端未付费时退出到毛玻璃状态的弹窗数据
+ (NSString *)fus_URL_liveGetPayRoomFrostedGlassData
{
return [FUSConfig.sharedInstanced.pathConfigs apiUrl:@"/payRoom/getFrostedGlassData"];
}
/// 切换付费模式V2 /// 切换付费模式V2
+ (NSString *)fus_URL_liveChangePay + (NSString *)fus_URL_liveChangePay
......
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