|
@@ -12,18 +12,1819 @@
|
|
|
#import <RongFaceBeautifier/RongFaceBeautifier.h>
|
|
|
#import "KSBeautySettingView.h"
|
|
|
#import "KSEnterLiveroomManager.h"
|
|
|
+#import "LiveroomTimeManager.h"
|
|
|
|
|
|
-@interface LiveRoomViewController ()
|
|
|
+#import "UserInfoManager.h"
|
|
|
+#import <RongIMKit/RongIMKit.h>
|
|
|
+#import "KSChatInputBarControl.h"
|
|
|
+#import "LiveRoomHeadView.h"
|
|
|
+#import "LiveRoomBottomView.h"
|
|
|
+#import "SeatContentView.h"
|
|
|
+#import "LiveSeatApplyView.h"
|
|
|
+#import "SeatTipsView.h"
|
|
|
+#import "KSLiveStreamVideo.h"
|
|
|
+#import "KSRCMessageModel.h"
|
|
|
+#import "KSChatroomMessageCenter.h"
|
|
|
+#import "KSChatroomTextCell.h"
|
|
|
+#import "LiveRoomAlertView.h"
|
|
|
+#import "LiveMoreDisplayView.h"
|
|
|
+#import "LiveAnimationView.h"
|
|
|
+#import "KSShareChooseViewController.h"
|
|
|
+#import "KSChatLiveMessage.h"
|
|
|
+typedef NS_ENUM(NSInteger, LIVEPAGE) {
|
|
|
+ LIVEPAGE_PREVIEW,
|
|
|
+ LIVEPAGE_LIVE,
|
|
|
+};
|
|
|
+
|
|
|
+@interface LiveRoomViewController ()<RCRTCEngineEventDelegate,RCRTCRoomEventDelegate,RCRTCStatusReportDelegate,UIGestureRecognizerDelegate,KSChatInputBarControlDelegate,UITableViewDataSource,UITableViewDelegate,LiveroomTimeManagerDelegate>
|
|
|
+
|
|
|
+@property (nonatomic, strong) LiveroomTimeManager *timeManager;
|
|
|
+
|
|
|
+@property (nonatomic, assign) LIVEPAGE pageType;
|
|
|
+
|
|
|
+@property (nonatomic, assign) BOOL isPauseLive; // 是否暂停直播
|
|
|
+
|
|
|
+@property (nonatomic, assign) BOOL isOtherLogin; // 是否被顶掉
|
|
|
+
|
|
|
+@property (nonatomic, strong) LivePreviewBodyView *previewPageView;
|
|
|
+
|
|
|
+@property (nonatomic, strong) RCRTCVideoView *preVideoView;
|
|
|
+
|
|
|
+@property (nonatomic, strong) KSBeautySettingView *settingView;
|
|
|
+
|
|
|
+@property (nonatomic, assign) BOOL isBeautyOn;
|
|
|
+
|
|
|
+@property (nonatomic, assign) int filterLevel;
|
|
|
+
|
|
|
+#pragma mark ------- 直播房间信息
|
|
|
+/*!
|
|
|
+ 身份状态 主讲人/观众
|
|
|
+ */
|
|
|
+@property (nonatomic, assign) RCRTCLiveRoleType liveRoleType;
|
|
|
+/// 主讲人id
|
|
|
+@property (nonatomic, strong) NSString *createrId;
|
|
|
+/// 主讲人名称
|
|
|
+@property (nonatomic, strong) NSString *createrName;
|
|
|
+/// 主讲人头像
|
|
|
+@property (nonatomic, strong) NSString *createrAvatal;
|
|
|
+
|
|
|
+// 是否禁止连麦
|
|
|
+@property (nonatomic, assign) BOOL enableSeat;
|
|
|
+// 是否禁止聊天
|
|
|
+@property (nonatomic, assign) BOOL enableChat;
|
|
|
+// 是否允许点赞
|
|
|
+@property (nonatomic, assign) BOOL enableLike;
|
|
|
+
|
|
|
+@property (nonatomic, assign) NSInteger likeCount;
|
|
|
+/// 房间人数
|
|
|
+@property (nonatomic, assign) NSInteger totalCount;
|
|
|
+
|
|
|
+#pragma mark ---- Live page
|
|
|
+
|
|
|
+@property (nonatomic, strong) UIView *livePageView;
|
|
|
+
|
|
|
+@property (nonatomic, strong) RCRTCRoom *room;
|
|
|
+
|
|
|
+@property (nonatomic, assign) BOOL isImConnected;
|
|
|
+
|
|
|
+@property (nonatomic, assign) BOOL hasSendWelcomeMessage;
|
|
|
+
|
|
|
+@property (nonatomic, strong) KSLiveStreamVideo *localVideo;
|
|
|
+
|
|
|
+@property (nonatomic, strong) UIView *liveVideoView;
|
|
|
+
|
|
|
+@property (nonatomic, strong) LiveRoomHeadView *headView;
|
|
|
+
|
|
|
+@property (nonatomic, copy) LiveRoomBottomView *bottomView;
|
|
|
+
|
|
|
+/// 连麦的视图
|
|
|
+@property (nonatomic, strong) SeatContentView *seatContainer;
|
|
|
+// 聊天UI
|
|
|
+/*!
|
|
|
+ 消息列表CollectionView和输入框都在这个view里
|
|
|
+ */
|
|
|
+@property(nonatomic, strong) UIView *messageContentView;
|
|
|
+
|
|
|
+/*!
|
|
|
+ 会话页面的TableView
|
|
|
+ */
|
|
|
+@property (nonatomic, strong) UITableView *conversationMessageTableView;
|
|
|
+
|
|
|
+/*!
|
|
|
+ 聊天内容的消息Cell数据模型的数据源
|
|
|
+
|
|
|
+ @discussion 数据源中存放的元素为消息Cell的数据模型,即RCDLiveMessageModel对象。
|
|
|
+ */
|
|
|
+@property(nonatomic, strong) NSMutableArray<KSRCMessageModel *> *conversationDataRepository;
|
|
|
+/**
|
|
|
+ 输入工具栏
|
|
|
+ */
|
|
|
+@property(nonatomic,strong) KSChatInputBarControl *inputBar;
|
|
|
+/**
|
|
|
+ * 是否需要滚动到底部
|
|
|
+ */
|
|
|
+@property(nonatomic, assign) BOOL isNeedScrollToButtom;
|
|
|
+
|
|
|
+@property (nonatomic, strong) LiveSeatApplyView *seatApplyView;
|
|
|
+
|
|
|
+@property (nonatomic, strong) NSMutableArray *seatApplyArray; // 申请连麦数组
|
|
|
+// 远端连麦用户
|
|
|
+@property (nonatomic, strong) NSMutableArray *remoteMemberArray;
|
|
|
+
|
|
|
+/// 连麦申请统计数据
|
|
|
+@property (nonatomic, strong) SeatTipsView *seatApplyTips;
|
|
|
+
|
|
|
+/// 提示窗
|
|
|
+@property (nonatomic, strong) LiveRoomAlertView *alertView;
|
|
|
+
|
|
|
+// 定时器
|
|
|
+@property (nonatomic, strong) dispatch_source_t timer;
|
|
|
+
|
|
|
+@property (nonatomic, strong) LiveMoreDisplayView *moreView;
|
|
|
+
|
|
|
+@property (nonatomic) LiveAnimationView *animationView;
|
|
|
+
|
|
|
+/// 直播课结束时间
|
|
|
+@property (nonatomic, strong) NSString *liveEndTime;
|
|
|
+
|
|
|
+/// 直播间自动关闭时间
|
|
|
+@property (nonatomic, assign) NSInteger expiredMinute;
|
|
|
|
|
|
@end
|
|
|
|
|
|
+
|
|
|
+
|
|
|
@implementation LiveRoomViewController
|
|
|
|
|
|
- (void)viewDidLoad {
|
|
|
[super viewDidLoad];
|
|
|
// Do any additional setup after loading the view.
|
|
|
+ self.ks_prefersNavigationBarHidden = YES;
|
|
|
+ self.isOtherLogin = NO;
|
|
|
+ [self registerOtherLoginNotice];
|
|
|
+ [self configUI];
|
|
|
+ [self configEngine];
|
|
|
+ self.pageType = LIVEPAGE_PREVIEW;
|
|
|
+}
|
|
|
+
|
|
|
+- (void)registerOtherLoginNotice {
|
|
|
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(liveroomLogOut) name:@"liveroomLogout" object:nil];
|
|
|
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(liveroomQuit) name:@"liveroomQuit" object:nil];
|
|
|
+}
|
|
|
+
|
|
|
+- (void)viewWillAppear:(BOOL)animated {
|
|
|
+ [super viewWillAppear:animated];
|
|
|
+ [UIApplication sharedApplication].idleTimerDisabled = YES;
|
|
|
+ [IQKeyboardManager sharedManager].enableAutoToolbar = NO;
|
|
|
+ [IQKeyboardManager sharedManager].enable = NO;
|
|
|
+ [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent;
|
|
|
+}
|
|
|
+
|
|
|
+- (void)viewWillDisappear:(BOOL)animated {
|
|
|
+ [super viewWillDisappear:animated];
|
|
|
+ [UIApplication sharedApplication].idleTimerDisabled = NO;
|
|
|
+ [IQKeyboardManager sharedManager].enableAutoToolbar = YES;
|
|
|
+ [IQKeyboardManager sharedManager].enable = YES;
|
|
|
+ if (@available(iOS 13.0, *)) {
|
|
|
+ [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleDarkContent;
|
|
|
+ } else {
|
|
|
+ // Fallback on earlier versions
|
|
|
+ [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleDefault;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+- (void)configUI {
|
|
|
+ self.previewPageView = [LivePreviewBodyView shareInstance];
|
|
|
+ [self.view addSubview:self.previewPageView];
|
|
|
+ [self.previewPageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
+ make.left.right.bottom.top.mas_equalTo(self.view);
|
|
|
+ }];
|
|
|
+ MJWeakSelf;
|
|
|
+ [self.previewPageView previewOperationCallback:^(PREVIEWLIVEACTION action) {
|
|
|
+ [weakSelf previewOperationAction:action];
|
|
|
+ }];
|
|
|
+ [[RCRTCBeautyEngine sharedInstance] reset];
|
|
|
+}
|
|
|
+
|
|
|
+- (void)configEngine {
|
|
|
+ if (!self.preVideoView) {
|
|
|
+ self.preVideoView = [[RCRTCVideoView alloc] init];
|
|
|
+ self.preVideoView.fillMode = RCRTCVideoFillModeAspectFill;
|
|
|
+
|
|
|
+ self.preVideoView.frameAnimated = NO;
|
|
|
+ [self.previewPageView.videoView addSubview:self.preVideoView];
|
|
|
+ [self.preVideoView mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
+ make.left.top.bottom.right.mas_equalTo(self.previewPageView.videoView);
|
|
|
+ }];
|
|
|
+ }
|
|
|
+ [[RCRTCEngine sharedInstance].defaultVideoStream setVideoView:self.preVideoView];
|
|
|
+ RCRTCVideoStreamConfig *videoConfig = [RCRTCEngine sharedInstance].defaultVideoStream.videoConfig;
|
|
|
+ videoConfig.videoSizePreset = RCRTCVideoSizePreset1920x1080;
|
|
|
+ [[RCRTCEngine sharedInstance].defaultVideoStream setVideoConfig:videoConfig];
|
|
|
+ [[RCRTCEngine sharedInstance].defaultVideoStream startCapture];
|
|
|
+ self.filterLevel = 50;
|
|
|
+}
|
|
|
+
|
|
|
+- (void)previewOperationAction:(PREVIEWLIVEACTION)action {
|
|
|
+ switch (action) {
|
|
|
+ case PREVIEWLIVEACTION_BACK: // 返回
|
|
|
+ {
|
|
|
+ if (self.isPauseLive) { // 退出RTC房间
|
|
|
+ [self quitRoomBackPreView:NO];
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ self.room = nil;
|
|
|
+ self.preVideoView = nil;
|
|
|
+ [[RCRTCEngine sharedInstance].defaultVideoStream stopCapture];
|
|
|
+ [self.navigationController dismissViewControllerAnimated:YES completion:nil];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case PREVIEWLIVEACTION_SWITCH: // 切换
|
|
|
+ {
|
|
|
+ [[RCRTCEngine sharedInstance].defaultVideoStream switchCamera];
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case PREVIEWLIVEACTION_BEAUTY: // 美颜
|
|
|
+ {
|
|
|
+ [self displayBeautyView];
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case PREVIEWLIVEACTION_SHARE: // 分享
|
|
|
+ {
|
|
|
+ [self shareLiveRoomMessage];
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case PREVIEWLIVEACTION_OPEN: // 进入直播间
|
|
|
+ {
|
|
|
+ [self showLiveView];
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+- (void)shareLiveRoomMessage {
|
|
|
+ // 选择群组分享
|
|
|
+ KSChatLiveMessage *liveShareMsg = [[KSChatLiveMessage alloc] init];
|
|
|
+ liveShareMsg.roomUID = self.roomId;
|
|
|
+ NSString *teacherName = UserDefaultObjectForKey(NicknameKey);
|
|
|
+ if ([NSString isEmptyString:teacherName]) {
|
|
|
+ teacherName = [NSString stringWithFormat:@"游客%@",UserDefaultObjectForKey(UIDKey)];
|
|
|
+ }
|
|
|
+ liveShareMsg.teacherName = teacherName;
|
|
|
+ liveShareMsg.teacherAvatar = UserDefaultObjectForKey(AvatarUrlKey);
|
|
|
+ liveShareMsg.liveDescMessage = self.liveContent;
|
|
|
+
|
|
|
+ KSShareChooseViewController *chooseCtrl = [[KSShareChooseViewController alloc] init];
|
|
|
+ chooseCtrl.msgContent = liveShareMsg;
|
|
|
+ [self.navigationController pushViewController:chooseCtrl animated:YES];
|
|
|
+}
|
|
|
+
|
|
|
+- (void)displayBeautyView {
|
|
|
+ [self displayBottomView:YES];
|
|
|
+ if (_settingView == nil) {
|
|
|
+
|
|
|
+ RCRTCBeautyOption *option = [[RCRTCBeautyEngine sharedInstance] getCurrentBeautyOption];
|
|
|
+ RCRTCBeautyFilter filter = [[RCRTCBeautyEngine sharedInstance] getCurrentBeautyFilter];
|
|
|
+ FILTER_TYPE type = [self getFilterType:filter];
|
|
|
+ MJWeakSelf;
|
|
|
+ [self.settingView evaluateMessageWithWhite:option.whitenessLevel smoothLevel:option.smoothLevel ruddyLevel:option.ruddyLevel brightLevel:option.brightLevel filter:type filterLevel:self.filterLevel callback:^(BOOL isOpenBeauty, NSInteger white, NSInteger smoothLevel, NSInteger ruddyLevel, NSInteger brightLevel, FILTER_TYPE type, int filterLevel) {
|
|
|
+ [weakSelf configSettingBeauty:YES white:white smoothLevel:smoothLevel ruddyLevel:ruddyLevel brightLevel:brightLevel filter:[self getRongBeautyWithType:type] filterLevel:filterLevel];
|
|
|
+ }];
|
|
|
+ }
|
|
|
+
|
|
|
+ [self.view addSubview:self.settingView];
|
|
|
+ [self.settingView mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
+ make.left.right.top.bottom.mas_equalTo(self.view);
|
|
|
+ }];
|
|
|
+}
|
|
|
+
|
|
|
+- (FILTER_TYPE)getFilterType:(RCRTCBeautyFilter)filter {
|
|
|
+ switch (filter) {
|
|
|
+ case RCRTCBeautyFilterNone:
|
|
|
+ return FILTER_TYPE_NONE;
|
|
|
+ case RCRTCBeautyFilterFresh:
|
|
|
+ return FILTER_TYPE_QINGXIN;
|
|
|
+ case RCRTCBeautyFilterEsthetic:
|
|
|
+ return FILTER_TYPE_WEIMEI;
|
|
|
+ case RCRTCBeautyFilterRomantic:
|
|
|
+ return FILTER_TYPE_LANGMAN;
|
|
|
+ default:
|
|
|
+ return FILTER_TYPE_NONE;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+- (RCRTCBeautyFilter)getRongBeautyWithType:(FILTER_TYPE)type {
|
|
|
+ switch (type) {
|
|
|
+ case FILTER_TYPE_NONE:
|
|
|
+ return RCRTCBeautyFilterNone;
|
|
|
+ case FILTER_TYPE_QINGXIN:
|
|
|
+ return RCRTCBeautyFilterFresh;
|
|
|
+ case FILTER_TYPE_WEIMEI:
|
|
|
+ return RCRTCBeautyFilterEsthetic;
|
|
|
+ case FILTER_TYPE_LANGMAN:
|
|
|
+ return RCRTCBeautyFilterRomantic;
|
|
|
+ default:
|
|
|
+ return RCRTCBeautyFilterNone;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+- (void)configSettingBeauty:(BOOL)isOn white:(NSInteger)whitenessLevel smoothLevel:(NSInteger)smoothLevel ruddyLevel:(NSInteger)ruddyLevel brightLevel:(NSInteger)brightLevel filter:(RCRTCBeautyFilter)filter filterLevel:(int)filterLevel {
|
|
|
+ self.isBeautyOn = isOn;
|
|
|
+ if (isOn) {
|
|
|
+ // 获取当前美颜参数
|
|
|
+ RCRTCBeautyOption *option = [[RCRTCBeautyEngine sharedInstance] getCurrentBeautyOption];
|
|
|
+ // 修改参数
|
|
|
+ option.whitenessLevel = whitenessLevel;
|
|
|
+ option.smoothLevel = smoothLevel;
|
|
|
+ option.ruddyLevel = ruddyLevel;
|
|
|
+ option.brightLevel = brightLevel;
|
|
|
+ // 设置美颜
|
|
|
+ [[RCRTCBeautyEngine sharedInstance] setBeautyOption:isOn option:option];
|
|
|
+ // 设置滤镜
|
|
|
+ [[RCRTCBeautyEngine sharedInstance] setBeautyFilter:filter];
|
|
|
+ // 设置滤镜强度
|
|
|
+ [[RCRTCBeautyEngine sharedInstance] setFilterIntensity:filterLevel];
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ [[RCRTCBeautyEngine sharedInstance] reset];
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+- (void)showLiveView {
|
|
|
+ if (self.isPauseLive) { // 直接切换页面
|
|
|
+ self.pageType = LIVEPAGE_LIVE;
|
|
|
+ [self.view addSubview:self.livePageView];
|
|
|
+ [self.livePageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
+ make.left.right.top.bottom.mas_equalTo(self.view);
|
|
|
+ }];
|
|
|
+ // 开启推流
|
|
|
+ [self startPublishStream];
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ [self showhud];
|
|
|
+ MJWeakSelf;
|
|
|
+ [KSEnterLiveroomManager queryLiveroomConfig:self.roomId callback:^(NSDictionary * _Nullable parm) {
|
|
|
+ [weakSelf removehub];
|
|
|
+ if (parm != nil) {
|
|
|
+ [weakSelf setupLiveroomConfig:parm];
|
|
|
+ [weakSelf createLivePageViewDisplay];
|
|
|
+ }
|
|
|
+ }];
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+- (void)startPublishStream {
|
|
|
+ self.pageType = LIVEPAGE_LIVE;
|
|
|
+ self.isPauseLive = NO;
|
|
|
+ [self publishLocalStream];
|
|
|
+}
|
|
|
+
|
|
|
+- (void)setupLiveroomConfig:(NSDictionary *)source {
|
|
|
+ self.liveRoleType = RCRTCLiveRoleTypeBroadcaster;
|
|
|
+ self.createrId = [source stringValueForKey:@"speakerId"];
|
|
|
+ self.createrName = [source stringValueForKey:@"speakerName"];
|
|
|
+ self.createrAvatal = [source stringValueForKey:@"speakerPic"];
|
|
|
+ self.likeCount = [source integerValueForKey:@"likeNum"]; // 点赞数
|
|
|
+ NSInteger lookCount = [source integerValueForKey:@"lookNum"];
|
|
|
+ self.totalCount = lookCount; // 观看人数
|
|
|
+ NSString *roomConfig = [source stringValueForKey:@"roomConfig"];
|
|
|
+ NSData *jsonData = [roomConfig dataUsingEncoding:NSUTF8StringEncoding];
|
|
|
+ NSError *err;
|
|
|
+ NSDictionary *configDic = [NSJSONSerialization JSONObjectWithData:jsonData
|
|
|
+ options:NSJSONReadingMutableContainers
|
|
|
+ error:&err];
|
|
|
+ if (configDic) {
|
|
|
+ self.enableChat = ![configDic boolValueForKey:@"whether_chat"];
|
|
|
+ self.enableSeat = ![configDic boolValueForKey:@"whether_mic"];
|
|
|
+ self.enableLike = ![configDic boolValueForKey:@"whether_like"];
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+- (void)createLivePageViewDisplay {
|
|
|
+ self.pageType = LIVEPAGE_LIVE;
|
|
|
+ self.isImConnected = [USER_MANAGER checkIMConnected];
|
|
|
+ [self registerNotification];
|
|
|
+ [self setupUI];
|
|
|
+ [self configIMConnect];
|
|
|
+ [self startTimer];
|
|
|
+}
|
|
|
+
|
|
|
+#pragma mark --- settingView
|
|
|
+- (KSBeautySettingView *)settingView {
|
|
|
+ if (!_settingView) {
|
|
|
+ _settingView = [KSBeautySettingView shareInstance];
|
|
|
+ MJWeakSelf;
|
|
|
+ [_settingView hiddenViewCallback:^{
|
|
|
+ [weakSelf displayBottomView:NO];
|
|
|
+ }];
|
|
|
+
|
|
|
+ }
|
|
|
+ return _settingView;
|
|
|
+}
|
|
|
+
|
|
|
+- (void)displayBottomView:(BOOL)isHidden {
|
|
|
+ if (isHidden) {
|
|
|
+ self.previewPageView.functionView.hidden = YES;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ self.previewPageView.functionView.hidden = NO;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+#pragma mark ------- Live page
|
|
|
+- (void)startTimer {
|
|
|
+ if (self.timer) {
|
|
|
+ dispatch_resume(self.timer);
|
|
|
+ }
|
|
|
+}
|
|
|
+- (void)registerNotification {
|
|
|
+
|
|
|
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(IMConnetedCallback) name:@"RongIMConnected" object:nil];
|
|
|
+ [KSChatroomMessageCenter registerMessageTypes];
|
|
|
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMessageNotification:) name:OnReceiveChatroomMessageNotification object:nil];
|
|
|
+
|
|
|
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appEnterBackground) name:@"appEnterBackground" object:nil];
|
|
|
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appBecomeActive) name:@"appBecomeActive" object:nil];
|
|
|
+ [self judgeAutoClose];
|
|
|
+}
|
|
|
+
|
|
|
+- (void)judgeAutoClose {
|
|
|
+ if (self.isTempRoom == NO) {
|
|
|
+ self.timeManager.autoCloseNetworkRoomTime = [self getCloseTime];
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+#pragma mark ------ enter back ground
|
|
|
+- (void)appEnterBackground {
|
|
|
+ self.isEnterBackground = YES;
|
|
|
+ if (self.isPauseLive == NO) { // 暂停推流
|
|
|
+ [self pauseLiveActionBack:NO];
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+- (void)appBecomeActive {
|
|
|
+ if (self.isEnterBackground && self.pageType == LIVEPAGE_LIVE && self.isOtherLogin == NO) {
|
|
|
+ // 开启推流
|
|
|
+ [self startPublishStream];
|
|
|
+ }
|
|
|
+ self.isEnterBackground = NO;
|
|
|
+}
|
|
|
+
|
|
|
+- (void)setupUI {
|
|
|
+ CGSize size = self.view.bounds.size;
|
|
|
+ [self.view addSubview:self.livePageView];
|
|
|
+ [self.livePageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
+ make.left.right.top.bottom.mas_equalTo(self.view);
|
|
|
+ }];
|
|
|
+
|
|
|
+ [self.livePageView addSubview:self.liveVideoView];
|
|
|
+ [self.liveVideoView mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
+ make.left.top.bottom.right.mas_equalTo(self.livePageView);
|
|
|
+ }];
|
|
|
+
|
|
|
+ [self.livePageView addSubview:self.headView];
|
|
|
+
|
|
|
+ [self.headView mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
+ make.left.right.mas_equalTo(self.livePageView);
|
|
|
+ make.height.mas_equalTo(90);
|
|
|
+ if (@available(iOS 11.0, *)) {
|
|
|
+ make.top.mas_equalTo(self.livePageView.mas_safeAreaLayoutGuideTop).offset(10);
|
|
|
+ } else {
|
|
|
+ // Fallback on earlier versions
|
|
|
+ make.top.mas_equalTo(self.livePageView.mas_top).offset(10);
|
|
|
+ }
|
|
|
+ }];
|
|
|
+ [self.livePageView addSubview:self.messageContentView];
|
|
|
+ [self.livePageView addSubview:self.bottomView];
|
|
|
+
|
|
|
+ self.headView.boardcastName.text = [NSString returnNoNullStringWithString:self.createrName];
|
|
|
+ if (![NSString isEmptyString:self.createrAvatal]) {
|
|
|
+ [self.headView.boardcastAvatal sd_setImageWithURL:[NSURL URLWithString:self.createrAvatal] placeholderImage:[UIImage imageNamed:@"teacher_logo"]];
|
|
|
+ }
|
|
|
+ [self countLikeMessageCount];
|
|
|
+
|
|
|
+ [self.headView mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
+ make.left.right.mas_equalTo(self.livePageView);
|
|
|
+ make.height.mas_equalTo(90);
|
|
|
+ if (@available(iOS 11.0, *)) {
|
|
|
+ make.top.mas_equalTo(self.livePageView.mas_safeAreaLayoutGuideTop).offset(10);
|
|
|
+ } else {
|
|
|
+ // Fallback on earlier versions
|
|
|
+ make.top.mas_equalTo(self.livePageView.mas_top).offset(10);
|
|
|
+ }
|
|
|
+ }];
|
|
|
+ [self.livePageView addSubview:self.messageContentView];
|
|
|
+ [self.livePageView addSubview:self.bottomView];
|
|
|
+
|
|
|
+ [self.bottomView mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
+ make.left.right.mas_equalTo(self.livePageView);
|
|
|
+ if (@available(iOS 11.0, *)) {
|
|
|
+ make.bottom.mas_equalTo(self.livePageView.mas_safeAreaLayoutGuideBottom).offset(-10);
|
|
|
+ } else {
|
|
|
+ // Fallback on earlier versions
|
|
|
+ make.bottom.mas_equalTo(self.livePageView.mas_bottom).offset(-10);
|
|
|
+ }
|
|
|
+ make.height.mas_equalTo(44);
|
|
|
+ }];
|
|
|
+
|
|
|
+ [self.messageContentView mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
+ make.left.mas_equalTo(self.livePageView.mas_left);
|
|
|
+ make.right.mas_equalTo(self.livePageView.mas_right);
|
|
|
+ make.bottom.mas_equalTo(self.bottomView.mas_top).offset(-10);
|
|
|
+ make.height.mas_equalTo(270);
|
|
|
+ }];
|
|
|
+ [self.livePageView addSubview:self.inputBar];
|
|
|
+ [_inputBar setBackgroundColor: [UIColor whiteColor]];
|
|
|
+
|
|
|
+ [_inputBar setFrame:CGRectMake(0, kScreenHeight, size.width , 50)];
|
|
|
+ [_inputBar setHidden:YES];
|
|
|
+
|
|
|
+ [self.messageContentView addSubview:self.conversationMessageTableView];
|
|
|
+ [self.conversationMessageTableView mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
+ make.left.top.mas_equalTo(self.messageContentView);
|
|
|
+ make.width.mas_equalTo(240);
|
|
|
+ make.bottom.mas_equalTo(self.messageContentView.mas_bottom);
|
|
|
+ }];
|
|
|
+
|
|
|
+ [self.livePageView addSubview:self.seatApplyTips];
|
|
|
+ [self.seatApplyTips hideView];
|
|
|
+ [self.seatApplyTips mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
+ make.bottom.mas_equalTo(self.bottomView.mas_top).offset(2);
|
|
|
+ make.height.mas_equalTo(20);
|
|
|
+ make.left.mas_equalTo(self.bottomView.mas_right).offset(-72);
|
|
|
+ }];
|
|
|
+
|
|
|
+ UITapGestureRecognizer *resetBottomTapGesture =[[UITapGestureRecognizer alloc]
|
|
|
+ initWithTarget:self
|
|
|
+ action:@selector(resetBottomGesture:)];
|
|
|
+ resetBottomTapGesture.delegate = self;
|
|
|
+ [self.livePageView addGestureRecognizer:resetBottomTapGesture];
|
|
|
+}
|
|
|
+
|
|
|
+- (void)joinChatRoom {
|
|
|
+
|
|
|
+ [[RCIMClient sharedRCIMClient] joinChatRoom:self.roomId messageCount:-1 success:^{
|
|
|
+ dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
+ [self addConstMessage];
|
|
|
+ });
|
|
|
+ KSLiveChatroomWelcome *joinChatroomMessage = [[KSLiveChatroomWelcome alloc] init];
|
|
|
+ [joinChatroomMessage setMsgId:[RCIM sharedRCIM].currentUserInfo.userId];
|
|
|
+ MJWeakSelf;
|
|
|
+ [self sendMessage:joinChatroomMessage displayMessage:NO callback:^(BOOL success) {
|
|
|
+ weakSelf.hasSendWelcomeMessage = YES;
|
|
|
+ }];
|
|
|
+ // 加入成功发送消息
|
|
|
+
|
|
|
+ } error:^(RCErrorCode status) {
|
|
|
+ if (status == RC_CHATROOM_NOT_EXIST || status == KICKED_FROM_CHATROOM || status == RC_PARAMETER_INVALID_CHATROOM) {
|
|
|
+ dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
+ [self MBPShow:@"加入聊天室失败"];
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }];
|
|
|
+}
|
|
|
+
|
|
|
+- (void)configIMConnect {
|
|
|
+ if (self.isImConnected == YES) {
|
|
|
+ [self connectionService];
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ MJWeakSelf;
|
|
|
+ [USER_MANAGER connectionIMCallback:^(BOOL isSuccess) {
|
|
|
+ dispatch_main_async_safe(^{
|
|
|
+ [weakSelf connectionService];
|
|
|
+ });
|
|
|
+ }];
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+- (void)IMConnetedCallback {
|
|
|
+
|
|
|
+ dispatch_main_async_safe(^{
|
|
|
+ // IM 连接成功回调
|
|
|
+ if (self.hasSendWelcomeMessage) { // 如果已经发送了进入消息
|
|
|
+ // 查询是否直播间开启
|
|
|
+ [KSNetworkingManager speakerCheckRoomInfoRequest:KS_GET roomUid:self.roomId success:^(NSDictionary * _Nonnull dic) {
|
|
|
+ if ([dic integerValueForKey:@"code"] == 200 && [dic boolValueForKey:@"status"]) {
|
|
|
+ // 回调信息
|
|
|
+ MJWeakSelf;
|
|
|
+ [self notiferJoinSuccessToServiceCallback:^{
|
|
|
+ [weakSelf MBPShow:@"IM连接成功"];
|
|
|
+ [weakSelf sendWelcomeMessage];
|
|
|
+ }];
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ [self MBPShow:MESSAGEKEY];
|
|
|
+ [self quitRoomBackPreView:NO];
|
|
|
+ }
|
|
|
+ } faliure:^(NSError * _Nonnull error) {
|
|
|
+
|
|
|
+ }];
|
|
|
+ }
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+- (void)sendWelcomeMessage {
|
|
|
+ MJWeakSelf;
|
|
|
+ [[RCIMClient sharedRCIMClient] joinExistChatRoom:self.roomId messageCount:-1 success:^{
|
|
|
+ KSLiveChatroomWelcome *joinChatroomMessage = [[KSLiveChatroomWelcome alloc] init];
|
|
|
+ [joinChatroomMessage setMsgId:[RCIM sharedRCIM].currentUserInfo.userId];
|
|
|
+ [self sendMessage:joinChatroomMessage displayMessage:NO callback:^(BOOL success) {
|
|
|
+ [weakSelf joinRTCRoom];
|
|
|
+ }];
|
|
|
+ } error:^(RCErrorCode status) {
|
|
|
+ NSLog(@"error code %zd" ,status);
|
|
|
+ }];
|
|
|
+}
|
|
|
+
|
|
|
+- (void)joinRTCRoom {
|
|
|
+ [self setRoleType];
|
|
|
+}
|
|
|
+
|
|
|
+- (void)liveroomLogOut {
|
|
|
+ self.isOtherLogin = YES;
|
|
|
+ [self MBPShow:@"该账号在其他设备上登录"];
|
|
|
+ [self quitRoomBackPreView:NO];
|
|
|
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
|
|
+
|
|
|
+ [[NSNotificationCenter defaultCenter] postNotificationName:@"backLoginView" object:nil];
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+- (void)liveroomQuit {
|
|
|
+ self.isOtherLogin = YES;
|
|
|
+ [self quitRoomBackPreView:NO];
|
|
|
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
|
|
+ [[NSNotificationCenter defaultCenter] postNotificationName:@"backLoginView" object:nil];
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+- (void)connectionService {
|
|
|
+ [self setRoleType];
|
|
|
+ [self joinChatRoom];
|
|
|
+}
|
|
|
+
|
|
|
+- (void)countLikeMessageCount {
|
|
|
+ NSInteger count = self.likeCount;
|
|
|
+ NSString *desc = @"";
|
|
|
+ if (count > 10000) {
|
|
|
+ count = count / 10000;
|
|
|
+ desc = [NSString stringWithFormat:@"本场点赞%zd万+",count];
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ desc = [NSString stringWithFormat:@"本场点赞%zd",count];
|
|
|
+ }
|
|
|
+ self.headView.likeCount.text = desc;
|
|
|
+}
|
|
|
+- (void)countMemberCount {
|
|
|
+ NSInteger count = self.totalCount;
|
|
|
+ NSString *desc = @"";
|
|
|
+ if (count > 10000) {
|
|
|
+ count = count / 10000;
|
|
|
+ desc = [NSString stringWithFormat:@"%zd万+人",count];
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ desc = [NSString stringWithFormat:@"%zd人",count];
|
|
|
+ }
|
|
|
+ self.headView.roomMemberCount.text = desc;
|
|
|
+}
|
|
|
+
|
|
|
+// 刷新seatView
|
|
|
+- (void)renderSeatView {
|
|
|
+ NSMutableArray *seatArray = [NSMutableArray array];
|
|
|
+ NSArray *remoteUserArray = [self.room.remoteUsers mutableCopy];
|
|
|
+ for (RCRTCRemoteUser *user in remoteUserArray) {
|
|
|
+ [seatArray addObject:user.userId];
|
|
|
+ }
|
|
|
+ if (seatArray.count) {
|
|
|
+ if (![self.livePageView.subviews containsObject:self.seatContainer]) {
|
|
|
+ [self.livePageView addSubview:self.seatContainer];
|
|
|
+ }
|
|
|
+
|
|
|
+ [self.seatContainer mas_remakeConstraints:^(MASConstraintMaker *make) {
|
|
|
+ make.left.right.mas_equalTo(self.livePageView);
|
|
|
+ make.top.mas_equalTo(self.headView.mas_bottom).offset(10);
|
|
|
+ make.height.mas_equalTo(80);
|
|
|
+ }];
|
|
|
+
|
|
|
+ self.seatContainer.seatMemberArray = [NSMutableArray arrayWithArray:seatArray];
|
|
|
+ [self.seatContainer refreshSeatUI];
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ [self removeSeatContainer];
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+- (void)removeSeatContainer {
|
|
|
+ if ([self.livePageView.subviews containsObject:self.seatContainer]) {
|
|
|
+ [self.seatContainer removeFromSuperview];
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
+- (void)setRoleType {
|
|
|
+ // 1.设置切换听筒为扬声器
|
|
|
+ [[RCRTCEngine sharedInstance] setDefaultAudioRouteToSpeaker:YES];
|
|
|
+ [RCRTCEngine sharedInstance].statusReportDelegate = self;
|
|
|
+ // 2.添加本地采集预览界面
|
|
|
+ [self setupLocalVideoView];
|
|
|
+ // 3.加入RTC房间
|
|
|
+ [self joinRTCLiveRoom];
|
|
|
+}
|
|
|
+
|
|
|
+// 添加本地采集预览页面
|
|
|
+- (void)setupLocalVideoView {
|
|
|
+ [self.liveVideoView addSubview:self.localVideo.canvesView];
|
|
|
+ [self.localVideo.canvesView mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
+ make.left.right.top.bottom.mas_equalTo(self.liveVideoView);
|
|
|
+ }];
|
|
|
+}
|
|
|
+
|
|
|
+#pragma mark ----- RCRTCStatusReportDelegate
|
|
|
+- (void)didReportStatusForm:(RCRTCStatusForm *)form {
|
|
|
+ BOOL isConnectedFailed = NO;
|
|
|
+ for (RCRTCStreamStat* stat in form.sendStats) {
|
|
|
+ if (stat.packetLoss == 1.0) {
|
|
|
+ isConnectedFailed = YES;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ [self showNetStatus:form.rtt networkLost:isConnectedFailed];
|
|
|
+
|
|
|
+// NSLog(@"%@",form.description);
|
|
|
+ // 网络状态差提示
|
|
|
+
|
|
|
+}
|
|
|
+- (void)showNetStatus:(NSInteger)rttValue networkLost:(BOOL)isFailed {
|
|
|
+ dispatch_main_async_safe((^{
|
|
|
+ if (isFailed) {
|
|
|
+ [self.headView.rttImage setImage:[UIImage imageNamed:@"live_networking_bad"]];
|
|
|
+ self.headView.msLabel.text = @"网络已断开";
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ self.headView.msLabel.text = [NSString stringWithFormat:@"%zdms",rttValue];
|
|
|
+ if (rttValue < 100) {
|
|
|
+ [self.headView.rttImage setImage:[UIImage imageNamed:@"live_networking_good"]];
|
|
|
+ }
|
|
|
+ else if (rttValue < 200) {
|
|
|
+ [self.headView.rttImage setImage:[UIImage imageNamed:@"live_networking_nomal"]];
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ [self.headView.rttImage setImage:[UIImage imageNamed:@"live_networking_bad"]];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }));
|
|
|
+}
|
|
|
+
|
|
|
+#pragma mark ---- RCRTCRoomEventDelegate
|
|
|
+// 远端发布流
|
|
|
+- (void)didPublishStreams:(NSArray<RCRTCInputStream *> *)streams {
|
|
|
+ [self subscribeRemoteResource:streams];
|
|
|
+ NSLog(@"didPublishStreams --------");
|
|
|
+}
|
|
|
+
|
|
|
+// 订阅远端流
|
|
|
+- (void)subscribeRemoteResource:(NSArray<RCRTCInputStream *> *)streams {
|
|
|
+ [self subscribeRemoteResource:streams isTiny:NO];
|
|
|
+}
|
|
|
+
|
|
|
+- (void)subscribeRemoteResource:(NSArray<RCRTCInputStream *> *)streams isTiny:(BOOL)isTiny {
|
|
|
+ // 订阅房间中远端用户音视频流资源
|
|
|
+ NSArray *tinyStream = isTiny ? streams : @[];
|
|
|
+ NSArray *ordinaryStream = isTiny ? @[] : streams;
|
|
|
+ MJWeakSelf;
|
|
|
+ [self.room.localUser subscribeStream:ordinaryStream
|
|
|
+ tinyStreams:tinyStream
|
|
|
+ completion:^(BOOL isSuccess, RCRTCCode desc) {
|
|
|
+ if (desc != RCRTCCodeSuccess) {
|
|
|
+ NSString *errorStr = [NSString stringWithFormat:@"订阅远端流失败:%ld", (long) desc];
|
|
|
+ [weakSelf MBPShow:errorStr];
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }];
|
|
|
+ [self renderSeatView];
|
|
|
+}
|
|
|
+
|
|
|
+- (void)didUnpublishStreams:(NSArray<RCRTCInputStream *> *)streams {
|
|
|
+ NSLog(@"didUnPublishStreams --------");
|
|
|
+ [self renderSeatView];
|
|
|
+}
|
|
|
+
|
|
|
+- (void)didOfflineUser:(RCRTCRemoteUser *)user {
|
|
|
+ [self renderSeatView];
|
|
|
+}
|
|
|
+- (void)didJoinUser:(RCRTCRemoteUser *)user {
|
|
|
+ NSLog(@"--didJoinUser-");
|
|
|
+// [self renderSeatView];
|
|
|
+}
|
|
|
+
|
|
|
+// 如果有远端用户离开房间
|
|
|
+- (void)didLeaveUser:(RCRTCRemoteUser *)user {
|
|
|
+ NSLog(@"--didLeaveUser-");
|
|
|
+ // 如果有人离开房间
|
|
|
+ if ([self judgeContainMember:user.userId]) {
|
|
|
+ [self removeMember:user.userId];
|
|
|
+ [self refreshSeatApplyView];
|
|
|
+ }
|
|
|
+ [self renderSeatView];
|
|
|
+}
|
|
|
+
|
|
|
+// 远端用户切换身份
|
|
|
+- (void)didSwitchRoleWithUser:(RCRTCRemoteUser *)user roleType:(RCRTCLiveRoleType)roleType {
|
|
|
+ if (roleType == RCRTCLiveRoleTypeBroadcaster) {
|
|
|
+ if ([self judgeContainUser:user.userId] == NO) {
|
|
|
+ [self.remoteMemberArray addObject:user];
|
|
|
+ // 刷新连麦成员状态数据
|
|
|
+ if ([self judgeContainMember:user.userId]) {
|
|
|
+ // 更新状态
|
|
|
+ [self updateMemberStatusConnecting:user.userId];
|
|
|
+ [self refreshSeatApplyView];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ [self removeMemberUserId:user.userId];
|
|
|
+ // 刷新连麦成员数据
|
|
|
+ if ([self judgeContainMember:user.userId]) {
|
|
|
+ [self removeMember:user.userId];
|
|
|
+ [self refreshSeatApplyView];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ [self renderSeatView];
|
|
|
+
|
|
|
+ NSLog(@"didSwitchRoleWithUser --------");
|
|
|
+}
|
|
|
+
|
|
|
+- (BOOL)judgeContainUser:(NSString *)userId {
|
|
|
+ BOOL containUser = NO;
|
|
|
+ for (RCRTCRemoteUser *remoteUser in self.remoteMemberArray) {
|
|
|
+ if ([remoteUser.userId isEqualToString:userId]) {
|
|
|
+ containUser = YES;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return containUser;
|
|
|
+}
|
|
|
+
|
|
|
+- (void)removeMemberUserId:(NSString *)userId {
|
|
|
+ for (RCRTCRemoteUser *remoteUser in self.remoteMemberArray) {
|
|
|
+ if ([remoteUser.userId isEqualToString:userId]) {
|
|
|
+ [self.remoteMemberArray removeObject:remoteUser];
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+#pragma mark - KSChatInputBarControlDelegate
|
|
|
+// 根据inputBar 回调来修改页面布局
|
|
|
+- (void)onInputBarControlContentSizeChanged:(CGRect)frame withAnimationDuration:(CGFloat)duration andAnimationCurve:(UIViewAnimationCurve)curve {
|
|
|
+ CGRect originFrame = _inputBar.frame;
|
|
|
+ __weak __typeof(&*self)weakSelf = self;
|
|
|
+ // 目前只使用y值即可 -- 只修改messageContentView高度,让展示消息view和输入框随之移动
|
|
|
+ [UIView animateWithDuration:duration animations:^{
|
|
|
+ [UIView setAnimationCurve:curve];
|
|
|
+ [weakSelf.inputBar setFrame:CGRectMake(0, frame.origin.y - originFrame.size.height, originFrame.size.width, originFrame.size.height)];
|
|
|
+ [UIView commitAnimations];
|
|
|
+ }];
|
|
|
+}
|
|
|
+
|
|
|
+// 发送消息
|
|
|
+- (void)onTouchSendButton:(NSString *)text {
|
|
|
+ [self touristSendMessage:text];
|
|
|
+}
|
|
|
+
|
|
|
+- (void)touristSendMessage:(NSString *)text {
|
|
|
+
|
|
|
+ RCTextMessage *rcTextMessage = [RCTextMessage messageWithContent:text];
|
|
|
+ MJWeakSelf;
|
|
|
+ [self sendMessage:rcTextMessage displayMessage:YES callback:^(BOOL success) {
|
|
|
+ [weakSelf setDefaultBottomViewStatus];
|
|
|
+ }];
|
|
|
+}
|
|
|
+
|
|
|
+#pragma mark ---- RTC
|
|
|
+- (void)joinRTCLiveRoom {
|
|
|
+ // 1.配置房间
|
|
|
+ RCRTCRoomConfig *config = [[RCRTCRoomConfig alloc] init];
|
|
|
+ config.roomType = RCRTCRoomTypeLive;
|
|
|
+ config.liveType = RCRTCLiveTypeAudioVideo;
|
|
|
+ config.roleType = RCRTCLiveRoleTypeBroadcaster;
|
|
|
+ __weak typeof(self) weakSelf = self;
|
|
|
+ [[RCRTCEngine sharedInstance] joinRoom:self.roomId config:config completion:^(RCRTCRoom * _Nullable room, RCRTCCode code) {
|
|
|
+ dispatch_main_async_safe(^{
|
|
|
+ __strong typeof(weakSelf) strongSelf = weakSelf;
|
|
|
+ if (code == RCRTCCodeSignalServerNotConnect || code == RCRTCCodeParameterError || code == RCRTCCodeNotInRTCRoom || code == RCRTCCodeRTCTokenIsNull || code == RCRTCCodeHttpTimeoutError || code == RCRTCCodeHttpError || code == RCRTCCodeVoIPNotAvailable) {
|
|
|
+ NSLog(@"%@",[NSString stringWithFormat:@"加入失败 code %ld",code]);
|
|
|
+ [strongSelf MBPShow:@"加入直播间失败"];
|
|
|
+// [strongSelf.navigationController dismissViewControllerAnimated:YES completion:nil];
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ [strongSelf notiferJoinSuccessToServiceCallback:^{
|
|
|
+
|
|
|
+ }];
|
|
|
+ if (room) {
|
|
|
+ strongSelf.room = room;
|
|
|
+ strongSelf.room.delegate = self;
|
|
|
+ }
|
|
|
+
|
|
|
+ [strongSelf countMemberCount];
|
|
|
+ // 发布本地视频流
|
|
|
+ if (strongSelf.isPauseLive == NO && strongSelf.isEnterBackground == NO) {
|
|
|
+ [strongSelf publishLocalStream];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ });
|
|
|
+ }];
|
|
|
+}
|
|
|
+
|
|
|
+- (void)publishLocalStream {
|
|
|
+ // 1.设置渲染视图渲染视图
|
|
|
+ [[RCRTCEngine sharedInstance].defaultVideoStream setVideoView:self.localVideo.canvesView];
|
|
|
+ // 2.设置视频流参数
|
|
|
+ RCRTCVideoStreamConfig *videoConfig = [RCRTCEngine sharedInstance].defaultVideoStream.videoConfig;
|
|
|
+ videoConfig.videoSizePreset = RCRTCVideoSizePreset1280x720;
|
|
|
+ videoConfig.videoFps = RCRTCVideoFPS30;
|
|
|
+ [[RCRTCEngine sharedInstance].defaultVideoStream setVideoConfig:videoConfig];
|
|
|
+ // 3.开始视频采集
|
|
|
+ [[RCRTCEngine sharedInstance].defaultVideoStream startCapture];
|
|
|
+ [RCRTCEngine sharedInstance].defaultVideoStream.enableTinyStream = NO;
|
|
|
+ [[RCRTCEngine sharedInstance].defaultAudioStream setAudioQuality:RCRTCAudioQualityMusicHigh Scenario:RCRTCAudioScenarioMusicChatRoom];
|
|
|
+
|
|
|
+ // 发布本地视频流到房间
|
|
|
+ MJWeakSelf;
|
|
|
+ [self.room.localUser publishDefaultLiveStreams:^(BOOL isSuccess, RCRTCCode code, RCRTCLiveInfo * _Nullable liveInfo) {
|
|
|
+ if (code == RCRTCCodeSuccess) {
|
|
|
+
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ [weakSelf MBPShow:@"视频流发布失败"];
|
|
|
+ }
|
|
|
+ }];
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+- (void)exitRoomCallback:(void(^)(BOOL success))callback {
|
|
|
+ [[RCRTCEngine sharedInstance].defaultVideoStream stopCapture];
|
|
|
+ _localVideo = nil;
|
|
|
+ _preVideoView = nil;
|
|
|
+ _room = nil;
|
|
|
+ MJWeakSelf;
|
|
|
+ [[RCRTCEngine sharedInstance] leaveRoom:^(BOOL isSuccess, RCRTCCode code) {
|
|
|
+ dispatch_main_async_safe(^{
|
|
|
+ [weakSelf sendLeaveMessageCallback:^(BOOL success) {
|
|
|
+ callback(success);
|
|
|
+ }];
|
|
|
+ });
|
|
|
+ }];
|
|
|
+}
|
|
|
+
|
|
|
+// 销毁房间
|
|
|
+- (void)distoryRoomCallback:(void(^)(BOOL success))callback {
|
|
|
+ [[RCRTCEngine sharedInstance].defaultVideoStream stopCapture];
|
|
|
+ _localVideo = nil;
|
|
|
+ _preVideoView = nil;
|
|
|
+ _room = nil;
|
|
|
+ __weak typeof(self) weakSelf = self;
|
|
|
+ [[RCRTCEngine sharedInstance] leaveRoom:^(BOOL isSuccess, RCRTCCode code) {
|
|
|
+ dispatch_main_async_safe(^{
|
|
|
+ __strong typeof(weakSelf) strongSelf = weakSelf;
|
|
|
+ [strongSelf sendLeaveMessageCallback:^(BOOL success) {
|
|
|
+ callback(success);
|
|
|
+ }];
|
|
|
+ });
|
|
|
+ }];
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+#pragma mark -- 加入直播间和退出直播间回到服务
|
|
|
+- (void)notiferJoinSuccessToServiceCallback:(void(^)(void))callback {
|
|
|
+ [KSNetworkingManager liveRoomJoinRoomRequest:KS_GET roomUid:self.roomId success:^(NSDictionary * _Nonnull dic) {
|
|
|
+ callback();
|
|
|
+ } faliure:^(NSError * _Nonnull error) {
|
|
|
+ callback();
|
|
|
+ }];
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+#pragma mark -- 退出直播间回掉服务
|
|
|
+- (void)quitNotiferService {
|
|
|
+ [KSNetworkingManager LiveroomQuit:KS_POST success:^(NSDictionary * _Nonnull dic) {
|
|
|
+ if ([dic integerValueForKey:@"errCode"] == 0) {
|
|
|
+ NSLog(@"success");
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ NSLog(@"----- error %@", [dic stringValueForKey:@"errMsg"]);
|
|
|
+ }
|
|
|
+ } faliure:^(NSError * _Nonnull error) {
|
|
|
+
|
|
|
+ }];
|
|
|
+}
|
|
|
+
|
|
|
+- (void)closeRoomNotiferService {
|
|
|
+ [KSNetworkingManager destroyLiveRoomRequest:KS_GET roomUid:self.roomId success:^(NSDictionary * _Nonnull dic) {
|
|
|
+ if ([dic integerValueForKey:@"errCode"] == 0) {
|
|
|
+ NSLog(@"success");
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ NSLog(@"----- error %@", [dic stringValueForKey:@"errMsg"]);
|
|
|
+ }
|
|
|
+ } faliure:^(NSError * _Nonnull error) {
|
|
|
+
|
|
|
+ }];
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+- (void)sendLeaveMessageCallback:(void(^)(BOOL success))callback {
|
|
|
+
|
|
|
+ RCUserInfo *currentUserInfo = [RCIM sharedRCIM].currentUserInfo;
|
|
|
+ KSLiveChatroomLeave *leaveMessage = [[KSLiveChatroomLeave alloc] init];
|
|
|
+ leaveMessage.userId = currentUserInfo.userId;
|
|
|
+ leaveMessage.userName = currentUserInfo.name;
|
|
|
+ [self sendMessage:leaveMessage displayMessage:NO callback:^(BOOL success) {
|
|
|
+ callback(success);
|
|
|
+ }];
|
|
|
+}
|
|
|
+
|
|
|
+- (void)quitChatRoom {
|
|
|
+ [[RCIMClient sharedRCIMClient] quitChatRoom:self.roomId success:^{
|
|
|
+ NSLog(@"sucess log out--");
|
|
|
+ } error:^(RCErrorCode status) {
|
|
|
+ NSLog(@"RCErrorCode------%ld ", (long)status);
|
|
|
+ }];
|
|
|
+}
|
|
|
+
|
|
|
+- (void)addConstMessage { // 固定欢迎词语
|
|
|
+ RCTextMessage *statement = [RCTextMessage messageWithContent:@"欢迎进入直播课堂,请遵守相关法规,禁止传播低俗、暴力等不良信息。为孩子创造健康绿色的学习环境。"];
|
|
|
+ statement.extra = @"statement";
|
|
|
+ RCMessage *constMessage = [[RCMessage alloc] initWithType:ConversationType_CHATROOM targetId:self.roomId direction:MessageDirection_SEND content:statement];
|
|
|
+ constMessage.content.senderUserInfo = [RCIM sharedRCIM].currentUserInfo;
|
|
|
+ [self appendAndDisplayMessage:constMessage];
|
|
|
+}
|
|
|
+
|
|
|
+#pragma mark - views init
|
|
|
+/**
|
|
|
+ * 接收到消息的回调
|
|
|
+ */
|
|
|
+- (void)didReceiveMessageNotification:(NSNotification *)notification {
|
|
|
+ NSDictionary *dic = notification.object;
|
|
|
+ __block RCMessage *rcMessage = dic[@"message"];
|
|
|
+ KSRCMessageModel *model = [[KSRCMessageModel alloc] initWithMessage:rcMessage];
|
|
|
+ model.userInfo = rcMessage.content.senderUserInfo;
|
|
|
+ if (model.conversationType == ConversationType_CHATROOM && [model.targetId isEqualToString:self.roomId]) {
|
|
|
+ __weak typeof(&*self) __blockSelf = self;
|
|
|
+ dispatch_main_async_safe((^{
|
|
|
+ // 对赞消息拦截 ,展示动画,不插入数据源 ,对于seat消息 和踢出消息,弹出alert
|
|
|
+ if (rcMessage) {
|
|
|
+ // 👍🏻消息
|
|
|
+ if ([rcMessage.content isMemberOfClass:[KSLiveChatroomLike class]]) {
|
|
|
+ KSLiveChatroomLike *likeMessage = (KSLiveChatroomLike *)rcMessage.content;
|
|
|
+ // 统计点赞数量
|
|
|
+ __blockSelf.likeCount += likeMessage.counts;
|
|
|
+ [__blockSelf countLikeMessageCount];
|
|
|
+ }
|
|
|
+ else if ([rcMessage.content isMemberOfClass:[KSLiveChatroomWelcome class]]) {
|
|
|
+ // 过滤自己发送的欢迎消息
|
|
|
+ if ([rcMessage.senderUserId isEqualToString:UserDefault(UIDKey)]) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 弹幕
|
|
|
+ RCUserInfo *userInfo = rcMessage.content.senderUserInfo;
|
|
|
+ NSString *userName = [userInfo.name stringByAppendingString:@""];
|
|
|
+ NSString *contentMsg = [NSString stringWithFormat:@"%@ 进入直播间",userName];
|
|
|
+ [__blockSelf showAnimationView:YES showMessag:contentMsg];
|
|
|
+
|
|
|
+ if ([__blockSelf judgeContainMember:rcMessage.senderUserId]) {
|
|
|
+ [__blockSelf removeMember:rcMessage.senderUserId];
|
|
|
+ [__blockSelf refreshSeatApplyView];
|
|
|
+ [__blockSelf renderSeatView];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if ([rcMessage.content isMemberOfClass:[KSLiveChatroomMemberUp class]]) {
|
|
|
+ KSLiveChatroomMemberUp *member = (KSLiveChatroomMemberUp *)rcMessage.content;
|
|
|
+ __blockSelf.totalCount = member.count;
|
|
|
+ [__blockSelf countMemberCount];
|
|
|
+ }
|
|
|
+ // 用户退出消息
|
|
|
+ else if ([rcMessage.content isMemberOfClass:[KSLiveChatroomLeave class]]) {
|
|
|
+ KSLiveChatroomLeave *memberLeaveMsg = (KSLiveChatroomLeave *)rcMessage.content;
|
|
|
+ if ([__blockSelf judgeContainMember:memberLeaveMsg.userId]) {
|
|
|
+ [__blockSelf removeMember:memberLeaveMsg.userId];
|
|
|
+ [__blockSelf refreshSeatApplyView];
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 连麦申请消息
|
|
|
+ else if ([rcMessage.content isMemberOfClass:[KSLiveChatroomSeatApply class]]) {
|
|
|
+ KSLiveChatroomSeatApply *seatApplyMessage = (KSLiveChatroomSeatApply *)rcMessage.content;
|
|
|
+
|
|
|
+ if (seatApplyMessage.type == SEATHANDLE_APPLY) { // 观众申请 加入申请中
|
|
|
+ LiveSeatMember *member = [[LiveSeatMember alloc] init];
|
|
|
+ member.avatar = seatApplyMessage.audienceAvatar;
|
|
|
+ member.name = seatApplyMessage.audienceName;
|
|
|
+ member.userId = seatApplyMessage.audienceId;
|
|
|
+ member.isConnected = NO;
|
|
|
+ if (![__blockSelf judgeContainMember:member.userId]) {
|
|
|
+ [__blockSelf.seatApplyArray addObject:member];
|
|
|
+ [__blockSelf refreshSeatApplyView];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if (seatApplyMessage.type == SEATHANDLE_CANCELAPPLY) { // 观众取消申请 从申请中剔除
|
|
|
+ if ([__blockSelf judgeContainMember:seatApplyMessage.audienceId]) {
|
|
|
+ [__blockSelf removeMember:seatApplyMessage.audienceId];
|
|
|
+ [__blockSelf refreshSeatApplyView];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 连麦回复消息(暂不处理)
|
|
|
+ else if ([rcMessage.content isMemberOfClass:[KSLiveChatroomSeatResponse class]]) {
|
|
|
+
|
|
|
+ }
|
|
|
+ else if ([rcMessage.content isMemberOfClass:[KSLiveChatroomDownSeat class]]) { // 观众下麦,从列表中移除
|
|
|
+ KSLiveChatroomDownSeat *downSeatMessage = (KSLiveChatroomDownSeat *)rcMessage.content;
|
|
|
+ if ([__blockSelf judgeContainMember:downSeatMessage.audienceId]) {
|
|
|
+ [__blockSelf removeMember:downSeatMessage.audienceId];
|
|
|
+ [__blockSelf refreshSeatApplyView];
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ else if ([rcMessage.content isMemberOfClass:[KSRCShopRushMessage class]]) {
|
|
|
+ KSRCShopRushMessage *rushMsg = (KSRCShopRushMessage *)rcMessage.content;
|
|
|
+
|
|
|
+ NSString *contentMsg = [NSString stringWithFormat:@"%@ 正在抢购",[NSString returnNoNullStringWithString:rushMsg.userName]];
|
|
|
+ [__blockSelf showAnimationView:NO showMessag:contentMsg];
|
|
|
+ }
|
|
|
+ else if ([rcMessage.content isMemberOfClass:[RCTextMessage class]]) {
|
|
|
+ [__blockSelf insertMessage:rcMessage userInfo:notification.userInfo];
|
|
|
+ }
|
|
|
+ else if ([rcMessage.content isMemberOfClass:[RCChatroomClose class]]) { // 直播间已关闭
|
|
|
+ [__blockSelf MBPShow:@"直播已结束"];
|
|
|
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
|
|
+ // 退出直播间
|
|
|
+ [__blockSelf quitRoomBackPreView:NO];
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }));
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+- (void)insertMessage:(RCMessage *)rcMessage userInfo:(NSDictionary *)userInfo {
|
|
|
+ // left
|
|
|
+ NSDictionary *leftDic = userInfo;
|
|
|
+ if (leftDic && [leftDic[@"left"] isEqual:@(0)]) {
|
|
|
+ self.isNeedScrollToButtom = YES;
|
|
|
+ }
|
|
|
+ [self appendAndDisplayMessage:rcMessage];
|
|
|
+}
|
|
|
+
|
|
|
+- (BOOL)judgeContainMember:(NSString *)userId {
|
|
|
+ for (LiveSeatMember *obj in self.seatApplyArray) {
|
|
|
+ if ([obj.userId isEqualToString:userId]) {
|
|
|
+ return YES;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return NO;
|
|
|
+}
|
|
|
+
|
|
|
+- (void)removeMember:(NSString *)memberId {
|
|
|
+ for (LiveSeatMember *member in self.seatApplyArray) {
|
|
|
+ if ([member.userId isEqualToString:memberId]) {
|
|
|
+ [self.seatApplyArray removeObject:member];
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+- (void)updateMemberStatusWaiting:(NSString *)userId {
|
|
|
+ for (LiveSeatMember *obj in self.seatApplyArray) {
|
|
|
+ if ([obj.userId isEqualToString:userId]) {
|
|
|
+ obj.isConnected = NO;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+- (void)updateMemberStatusConnecting:(NSString *)userId {
|
|
|
+ for (LiveSeatMember *obj in self.seatApplyArray) {
|
|
|
+ if ([obj.userId isEqualToString:userId]) {
|
|
|
+ obj.isConnected = YES;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+- (void)refreshSeatApplyView {
|
|
|
+ if (self.seatApplyArray.count) {
|
|
|
+ [self showSeatTips:self.seatApplyArray.count];
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ [self hideSeatTips];
|
|
|
+ }
|
|
|
+ [self.seatApplyView refreshSeatApplyTable:self.seatApplyArray];
|
|
|
+}
|
|
|
+
|
|
|
+- (void)showSeatTips:(NSInteger)count {
|
|
|
+ NSString *countDesc = count >= 100 ? @"99+" : [NSString stringWithFormat:@"%zd",count];
|
|
|
+ [self.seatApplyTips configCountMessage:countDesc];
|
|
|
+ [self.seatApplyTips showTipsView];
|
|
|
+}
|
|
|
+
|
|
|
+- (void)hideSeatTips {
|
|
|
+ [self.seatApplyTips hideView];
|
|
|
+}
|
|
|
+// 发送人数同步消息
|
|
|
+- (void)sendMemberCountMessage {
|
|
|
+ KSLiveChatroomMemberCount *syncMessage = [[KSLiveChatroomMemberCount alloc] init];
|
|
|
+ syncMessage.count = self.totalCount;
|
|
|
+
|
|
|
+ [self sendMessage:syncMessage displayMessage:NO callback:^(BOOL success) {
|
|
|
+
|
|
|
+ }];
|
|
|
+}
|
|
|
+
|
|
|
+#pragma mark ----- time manager delegate
|
|
|
+- (void)quitClassroomNotifer {
|
|
|
+ [self MBPShow:@"直播课已结束!"];
|
|
|
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
|
|
+ [self quitRoomBackPreView:NO];
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+#pragma mark - gesture and button action
|
|
|
+- (void)resetBottomGesture:(UIGestureRecognizer *)gestureRecognizer {
|
|
|
+ if (gestureRecognizer.state == UIGestureRecognizerStateEnded) {
|
|
|
+ [self setDefaultBottomViewStatus];
|
|
|
+ }
|
|
|
+}
|
|
|
+- (void)setDefaultBottomViewStatus {
|
|
|
+ [self.inputBar setInputBarStatus:KSBottomBarStatusDefault];
|
|
|
+ [self.inputBar setHidden:YES];
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+#pragma mark ---- sendMessage/showMessage
|
|
|
+- (void)sendMessage:(RCMessageContent *)messageContent displayMessage:(BOOL)displayMessage callback:(void(^)(BOOL success))callback {
|
|
|
+ if (_roomId == nil) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ messageContent.senderUserInfo = [RCIM sharedRCIM].currentUserInfo;
|
|
|
+ if (messageContent == nil) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ __weak typeof(&*self) __weakself = self;
|
|
|
+ [KSChatroomMessageCenter sendChatMessage:self.roomId content:messageContent success:^(long messageId) {
|
|
|
+ dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
+ RCMessage *message = [[RCMessage alloc] initWithType:ConversationType_CHATROOM targetId:__weakself.roomId direction:MessageDirection_SEND content:messageContent];
|
|
|
+ message.content.senderUserInfo = [RCIM sharedRCIM].currentUserInfo;
|
|
|
+
|
|
|
+ message.senderUserId = UserDefault(UIDKey);
|
|
|
+ if (displayMessage) {
|
|
|
+ [__weakself appendAndDisplayMessage:message];
|
|
|
+ }
|
|
|
+ [__weakself.inputBar clearInputView];
|
|
|
+ callback(YES);
|
|
|
+ });
|
|
|
+
|
|
|
+ } error:^(RCErrorCode errorCode, long messageId) {
|
|
|
+ if (errorCode == RC_CHATROOM_NOT_EXIST) {
|
|
|
+ dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
+ [self MBPShow:@"聊天已被解散,请退出后重进。"];
|
|
|
+ });
|
|
|
+ }
|
|
|
+ dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
+ [__weakself.inputBar clearInputView];
|
|
|
+ NSLog(@"发送失败,errorcode is: %ld",(long)errorCode);
|
|
|
+ callback(NO);
|
|
|
+ });
|
|
|
+ }];
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 将消息加入本地数组
|
|
|
+ */
|
|
|
+- (void)appendAndDisplayMessage:(RCMessage *)rcMessage {
|
|
|
+ if (!rcMessage) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ KSRCMessageModel *model = [[KSRCMessageModel alloc] initWithMessage:rcMessage];
|
|
|
+ model.userInfo = rcMessage.content.senderUserInfo;
|
|
|
+ if (!model.userInfo) {
|
|
|
+ model.userInfo = [RCIMClient sharedRCIMClient].currentUserInfo;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ([self appendMessageModel:model]) {
|
|
|
+ NSIndexPath *indexPath =
|
|
|
+ [NSIndexPath indexPathForItem:self.conversationDataRepository.count - 1
|
|
|
+ inSection:0];
|
|
|
+ if ([self.conversationMessageTableView numberOfRowsInSection:0] !=
|
|
|
+ self.conversationDataRepository.count - 1) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // view刷新
|
|
|
+ [self.conversationMessageTableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
|
|
|
+ if ([self isAtTheBottomOfTableView] || self.isNeedScrollToButtom) {
|
|
|
+ [self scrollToBottomAnimated:YES];
|
|
|
+ self.isNeedScrollToButtom=NO;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 如果当前会话没有这个消息id,把消息加入本地数组
|
|
|
+ */
|
|
|
+- (BOOL)appendMessageModel:(KSRCMessageModel *)model {
|
|
|
+
|
|
|
+ if (!model.content) {
|
|
|
+ return NO;
|
|
|
+ }
|
|
|
+ //这里可以根据消息类型来决定是否显示,如果不希望显示直接return NO
|
|
|
+
|
|
|
+ //数量不可能无限制的大,这里限制收到消息过多时,就对显示消息数量进行限制。
|
|
|
+ //用户可以手动下拉更多消息,查看更多历史消息。
|
|
|
+ if (self.conversationDataRepository.count>100) {
|
|
|
+ // NSRange range = NSMakeRange(0, 1);
|
|
|
+ KSRCMessageModel *message = self.conversationDataRepository[0];
|
|
|
+ [[RCIMClient sharedRCIMClient]deleteMessages:@[@(message.messageId)]];
|
|
|
+ [self.conversationDataRepository removeObjectAtIndex:0];
|
|
|
+ [self.conversationMessageTableView reloadData];
|
|
|
+ }
|
|
|
+
|
|
|
+ [self.conversationDataRepository addObject:model];
|
|
|
+ return YES;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 判断消息是否在collectionView的底部
|
|
|
+ *
|
|
|
+ * @return 是否在底部
|
|
|
+ */
|
|
|
+- (BOOL)isAtTheBottomOfTableView {
|
|
|
+ if (self.conversationMessageTableView.contentSize.height <= self.conversationMessageTableView.frame.size.height) {
|
|
|
+ return YES;
|
|
|
+ }
|
|
|
+ if(self.conversationMessageTableView.contentOffset.y +200 >= (self.conversationMessageTableView.contentSize.height - self.conversationMessageTableView.frame.size.height)) {
|
|
|
+ return YES;
|
|
|
+ }else{
|
|
|
+ return NO;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 消息滚动到底部
|
|
|
+ *
|
|
|
+ * @param animated 是否开启动画效果
|
|
|
+ */
|
|
|
+- (void)scrollToBottomAnimated:(BOOL)animated {
|
|
|
+ if ([self.conversationMessageTableView numberOfSections] == 0) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ NSUInteger finalRow = MAX(0, [self.conversationMessageTableView numberOfRowsInSection:0] - 1);
|
|
|
+ if (0 == finalRow) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ NSIndexPath *finalIndexPath =
|
|
|
+ [NSIndexPath indexPathForItem:finalRow inSection:0];
|
|
|
+ [self.conversationMessageTableView scrollToRowAtIndexPath:finalIndexPath atScrollPosition:UITableViewScrollPositionTop animated:animated];
|
|
|
+}
|
|
|
+/*
|
|
|
+#pragma mark - Navigation
|
|
|
+
|
|
|
+// In a storyboard-based application, you will often want to do a little preparation before navigation
|
|
|
+- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
|
|
|
+ // Get the new view controller using [segue destinationViewController].
|
|
|
+ // Pass the selected object to the new view controller.
|
|
|
+}
|
|
|
+*/
|
|
|
+
|
|
|
+#pragma mark ----- table data source
|
|
|
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
|
|
+ return self.conversationDataRepository.count;
|
|
|
+}
|
|
|
+
|
|
|
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
|
|
+ KSRCMessageModel *model = [self.conversationDataRepository objectAtIndex:indexPath.row];
|
|
|
+ RCMessageContent *messageContent = model.content;
|
|
|
+ KSChatroomTextCell *cell = [tableView dequeueReusableCellWithIdentifier:@"KSChatroomTextCell"];
|
|
|
+ if(!cell){
|
|
|
+ cell = [[KSChatroomTextCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"KSChatroomTextCell"];
|
|
|
+ }
|
|
|
+ if ([messageContent isMemberOfClass:[RCTextMessage class]] || [messageContent isMemberOfClass:[KSLiveChatroomWelcome class]] || [messageContent isMemberOfClass:[KSLiveChatroomLike class]] || [messageContent isMemberOfClass:[KSLiveChatroomSeatApply class]] || [messageContent isMemberOfClass:[KSLiveChatroomSeatResponse class]]){
|
|
|
+ [cell setDataModel:model createrId:self.createrId];
|
|
|
+ }
|
|
|
+ return cell;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+#pragma mark --- lazying
|
|
|
+- (UIView *)livePageView {
|
|
|
+ if (!_livePageView) {
|
|
|
+ _livePageView = [[UIView alloc] init];
|
|
|
+ _livePageView.backgroundColor = HexRGB(0x25292e);
|
|
|
+ }
|
|
|
+ return _livePageView;
|
|
|
+}
|
|
|
+
|
|
|
+- (UIView *)liveVideoView {
|
|
|
+ if (!_liveVideoView) {
|
|
|
+ _liveVideoView = [[UIView alloc] init];
|
|
|
+ _liveVideoView.backgroundColor = [UIColor clearColor];
|
|
|
+ }
|
|
|
+ return _liveVideoView;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+- (LiveRoomHeadView *)headView {
|
|
|
+ if (!_headView) {
|
|
|
+ _headView = [LiveRoomHeadView shareInstance];
|
|
|
+ }
|
|
|
+ return _headView;
|
|
|
+}
|
|
|
+
|
|
|
+- (LiveRoomBottomView *)bottomView {
|
|
|
+ if (!_bottomView) {
|
|
|
+ _bottomView = [LiveRoomBottomView shareInstance];
|
|
|
+ MJWeakSelf;
|
|
|
+ [_bottomView bottomClickAction:^(LIVEROOMACTION action) {
|
|
|
+ [weakSelf bottomViewAction:action];
|
|
|
+ }];
|
|
|
+ }
|
|
|
+ return _bottomView;
|
|
|
+}
|
|
|
+
|
|
|
+- (void)bottomViewAction:(LIVEROOMACTION)action {
|
|
|
+ switch (action) {
|
|
|
+ case LIVEROOMACTION_CHAT: // 聊天
|
|
|
+ {
|
|
|
+ [_inputBar setHidden:NO];
|
|
|
+ [_inputBar setInputBarStatus:KSBottomBarStatusKeyboard];
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case LIVEROOMACTION_SEAT: // 呼出连麦页面
|
|
|
+ {
|
|
|
+ [self displaySeatView];
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case LIVEROOMACTION_QUIT: // 退出
|
|
|
+ {
|
|
|
+ [self showMoreView];
|
|
|
+ }
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+- (void)showMoreView {
|
|
|
+ [self.view addSubview:self.moreView];
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+- (SeatTipsView *)seatApplyTips {
|
|
|
+ if (!_seatApplyTips) {
|
|
|
+ _seatApplyTips = [[SeatTipsView alloc] init];
|
|
|
+ }
|
|
|
+ return _seatApplyTips;
|
|
|
+}
|
|
|
+- (void)displaySeatView {
|
|
|
+ [self.view addSubview:self.seatApplyView];
|
|
|
+ [self refreshSeatApplyView];
|
|
|
+}
|
|
|
+
|
|
|
+- (void)closeRoomAction {
|
|
|
+ MJWeakSelf;
|
|
|
+ self.alertView = [LiveRoomAlertView liveroomAlertWithTitle:@"结束直播后,不可再次开启" leftButtonTitle:@"取消" rightTitle:@"结束直播" inView:self.view cancel:^{
|
|
|
+
|
|
|
+ } confirm:^{
|
|
|
+ [weakSelf distoryRoomAction];
|
|
|
+ }];
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+- (void)pauseAction {
|
|
|
+ MJWeakSelf;
|
|
|
+ self.alertView = [LiveRoomAlertView liveroomAlertWithTitle:@"暂停后观众将无法看到视频画面" leftButtonTitle:@"取消" rightTitle:@"暂停直播" inView:self.view cancel:^{
|
|
|
+
|
|
|
+ } confirm:^{
|
|
|
+ [weakSelf quitRoomBackPreView:YES];
|
|
|
+ }];
|
|
|
+}
|
|
|
+
|
|
|
+- (void)distoryRoomAction {
|
|
|
+ MJWeakSelf;
|
|
|
+ [self distoryRoomCallback:^(BOOL success) {
|
|
|
+ [weakSelf closeRoomNotiferService];
|
|
|
+ [weakSelf quitChatRoom];
|
|
|
+ weakSelf.room = nil;
|
|
|
+ [weakSelf.navigationController dismissViewControllerAnimated:YES completion:nil];
|
|
|
+ }];
|
|
|
+}
|
|
|
+- (void)pauseLiveActionBack:(BOOL)backPreView {
|
|
|
+ KSRCPauseLiveMessage *pauseMsg = [[KSRCPauseLiveMessage alloc] init];
|
|
|
+ MJWeakSelf;
|
|
|
+ [self sendMessage:pauseMsg displayMessage:NO callback:^(BOOL success) {
|
|
|
+ if (backPreView) {
|
|
|
+ [weakSelf.moreView hideView];
|
|
|
+ weakSelf.isPauseLive = YES;
|
|
|
+ weakSelf.pageType = LIVEPAGE_PREVIEW;
|
|
|
+ [weakSelf.livePageView removeFromSuperview];
|
|
|
+ [weakSelf configEngine];
|
|
|
+ }
|
|
|
+ }];
|
|
|
+
|
|
|
+ [self.room.localUser unpublishDefaultLiveStreams:^(BOOL isSuccess, RCRTCCode code) {
|
|
|
+ if (isSuccess) {
|
|
|
+
|
|
|
+ }
|
|
|
+ }];
|
|
|
+}
|
|
|
+
|
|
|
+- (void)quitRoomBackPreView:(BOOL)backPreView {
|
|
|
+ if (backPreView) { // 暂停
|
|
|
+ [self pauseLiveActionBack:YES];
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ if (self.pageType == LIVEPAGE_PREVIEW && self.isPauseLive == NO) {
|
|
|
+ self.room = nil;
|
|
|
+ self.preVideoView = nil;
|
|
|
+ [[RCRTCEngine sharedInstance].defaultVideoStream stopCapture];
|
|
|
+ [self.navigationController dismissViewControllerAnimated:YES completion:nil];
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ MJWeakSelf;
|
|
|
+ [self exitRoomCallback:^(BOOL success) {
|
|
|
+ // quit 接口
|
|
|
+ [weakSelf quitNotiferService];
|
|
|
+ [weakSelf quitChatRoom];
|
|
|
+ [weakSelf.moreView hideView];
|
|
|
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
|
|
+ [weakSelf.navigationController dismissViewControllerAnimated:YES completion:nil];
|
|
|
+ });
|
|
|
+ }];
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+- (KSLiveStreamVideo *)localVideo {
|
|
|
+ if (!_localVideo) {
|
|
|
+ _localVideo = [KSLiveStreamVideo LocalStreamVideo];
|
|
|
+ }
|
|
|
+ return _localVideo;
|
|
|
+}
|
|
|
+
|
|
|
+- (NSMutableArray *)remoteMemberArray {
|
|
|
+ if (!_remoteMemberArray) {
|
|
|
+ _remoteMemberArray = [NSMutableArray array];
|
|
|
+ }
|
|
|
+ return _remoteMemberArray;
|
|
|
+}
|
|
|
+
|
|
|
+- (UIView *)messageContentView {
|
|
|
+ if (!_messageContentView) {
|
|
|
+ _messageContentView = [[UIView alloc] init];
|
|
|
+ [_messageContentView setBackgroundColor: [UIColor clearColor]];
|
|
|
+ }
|
|
|
+ return _messageContentView;
|
|
|
+}
|
|
|
+
|
|
|
+- (NSMutableArray<KSRCMessageModel *> *)conversationDataRepository {
|
|
|
+ if (!_conversationDataRepository) {
|
|
|
+ _conversationDataRepository = [NSMutableArray array];
|
|
|
+ }
|
|
|
+ return _conversationDataRepository;
|
|
|
+}
|
|
|
+- (KSChatInputBarControl *)inputBar {
|
|
|
+ if (!_inputBar) {
|
|
|
+ _inputBar = [[KSChatInputBarControl alloc] initWithStatus:KSBottomBarStatusDefault];
|
|
|
+ [_inputBar setDelegate:self];
|
|
|
+ }
|
|
|
+ return _inputBar;
|
|
|
+}
|
|
|
+
|
|
|
+- (UITableView *)conversationMessageTableView {
|
|
|
+ if (!_conversationMessageTableView) {
|
|
|
+ _conversationMessageTableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
|
|
|
+ _conversationMessageTableView.backgroundColor = [UIColor clearColor];
|
|
|
+ _conversationMessageTableView.separatorStyle = UITableViewCellSeparatorStyleNone;
|
|
|
+ _conversationMessageTableView.dataSource = self;
|
|
|
+ _conversationMessageTableView.delegate = self;
|
|
|
+ _conversationMessageTableView.rowHeight = UITableViewAutomaticDimension;
|
|
|
+ _conversationMessageTableView.estimatedRowHeight = 40.0f;
|
|
|
+ _conversationMessageTableView.showsVerticalScrollIndicator = NO;
|
|
|
+ [_conversationMessageTableView registerClass:[KSChatroomTextCell class] forCellReuseIdentifier:@"KSChatroomTextCell"];
|
|
|
+ }
|
|
|
+ return _conversationMessageTableView;
|
|
|
+}
|
|
|
+
|
|
|
+- (SeatContentView *)seatContainer {
|
|
|
+ if (!_seatContainer) {
|
|
|
+ _seatContainer = [[SeatContentView alloc] init];
|
|
|
+ }
|
|
|
+ return _seatContainer;
|
|
|
+}
|
|
|
+
|
|
|
+- (LiveSeatApplyView *)seatApplyView {
|
|
|
+ if (!_seatApplyView) {
|
|
|
+ _seatApplyView = [LiveSeatApplyView shareInstance];
|
|
|
+ _seatApplyView.frame = CGRectMake(0, 0, kScreenWidth, kScreenHeight);
|
|
|
+ MJWeakSelf;
|
|
|
+ [_seatApplyView operationMemberAction:^(LIVESEATACTION action, LiveSeatMember * _Nonnull member) {
|
|
|
+ [weakSelf opreationSeatStudentAction:action member:member];
|
|
|
+ }];
|
|
|
+ }
|
|
|
+ return _seatApplyView;
|
|
|
+}
|
|
|
+
|
|
|
+- (void)opreationSeatStudentAction:(LIVESEATACTION)action member:(LiveSeatMember *)member {
|
|
|
+ switch (action) {
|
|
|
+ case LIVESEATACTION_APPROVE: // 同意
|
|
|
+ {
|
|
|
+ KSLiveChatroomSeatResponse *responseMessage = [[KSLiveChatroomSeatResponse alloc] init];
|
|
|
+ responseMessage.type = SEATRESPONSE_TEACHERAPPROVE;
|
|
|
+ responseMessage.teacherId = self.createrId;
|
|
|
+ responseMessage.teacherName = self.createrName;
|
|
|
+ responseMessage.audienceId = member.userId;
|
|
|
+ responseMessage.audienceName = member.name;
|
|
|
+ MJWeakSelf;
|
|
|
+ [self sendMessage:responseMessage displayMessage:NO callback:^(BOOL success) {
|
|
|
+ [weakSelf refreshSeatArrayRemoveMember:NO member:member];
|
|
|
+ }];
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case LIVESEATACTION_REJECT: // 拒绝
|
|
|
+ {
|
|
|
+ KSLiveChatroomSeatResponse *responseMessage = [[KSLiveChatroomSeatResponse alloc] init];
|
|
|
+ responseMessage.type = SEATRESPONSE_TEACHERREJECT;
|
|
|
+ responseMessage.teacherId = self.createrId;
|
|
|
+ responseMessage.teacherName = self.createrName;
|
|
|
+ responseMessage.audienceId = member.userId;
|
|
|
+ responseMessage.audienceName = member.name;
|
|
|
+ MJWeakSelf;
|
|
|
+ [self sendMessage:responseMessage displayMessage:NO callback:^(BOOL success) {
|
|
|
+ [weakSelf refreshSeatArrayRemoveMember:YES member:member];
|
|
|
+ }];
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case LIVESEATACTION_KICK: // 下麦
|
|
|
+ {
|
|
|
+
|
|
|
+ KSLiveChatroomSeatApply *kickSeatMessage = [[KSLiveChatroomSeatApply alloc] init];
|
|
|
+ kickSeatMessage.type = SEATHANDLE_KICKSEAT;
|
|
|
+ kickSeatMessage.teacherId = self.createrId;
|
|
|
+ kickSeatMessage.teacherName = self.createrName;
|
|
|
+ kickSeatMessage.audienceId = member.userId;
|
|
|
+ kickSeatMessage.audienceName = member.name;
|
|
|
+ MJWeakSelf;
|
|
|
+ [self sendMessage:kickSeatMessage displayMessage:NO callback:^(BOOL success) {
|
|
|
+ [weakSelf refreshSeatArrayRemoveMember:YES member:member];
|
|
|
+ }];
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+- (void)refreshSeatArrayRemoveMember:(BOOL)isRemove member:(LiveSeatMember *)member {
|
|
|
+ if (isRemove) {
|
|
|
+ [self.seatApplyArray removeObject:member];
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ member.isConnected = YES;
|
|
|
+ }
|
|
|
+ [self refreshSeatApplyView];
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+- (NSMutableArray *)seatApplyArray {
|
|
|
+ if (!_seatApplyArray) {
|
|
|
+ _seatApplyArray = [NSMutableArray array];
|
|
|
+ }
|
|
|
+ return _seatApplyArray;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+- (LiveMoreDisplayView *)moreView {
|
|
|
+ if (!_moreView) {
|
|
|
+ _moreView = [LiveMoreDisplayView shareInstance];
|
|
|
+ _moreView.frame = CGRectMake(0, 0, KPortraitWidth, KPortraitHeight);
|
|
|
+ MJWeakSelf;
|
|
|
+ [_moreView operationQuitAction:^(BOOL isCloseRoom) {
|
|
|
+ [weakSelf leaveRoom:isCloseRoom];
|
|
|
+ }];
|
|
|
+ }
|
|
|
+ return _moreView;
|
|
|
+}
|
|
|
+
|
|
|
+- (void)leaveRoom:(BOOL)closeRoom {
|
|
|
+ if (closeRoom) {
|
|
|
+ [self closeRoomAction];
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ [self pauseAction];
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+- (LiveroomTimeManager *)timeManager {
|
|
|
+ if (!_timeManager) {
|
|
|
+ _timeManager = [[LiveroomTimeManager alloc] initWithDelegate:self];
|
|
|
+ }
|
|
|
+ return _timeManager;
|
|
|
+}
|
|
|
+
|
|
|
+- (NSInteger)getCloseTime {
|
|
|
+ NSDateFormatter *formatter = [NSObject getDateformatter];
|
|
|
+ [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
|
|
|
+ NSDate *currentDate = [NSDate date];
|
|
|
+ NSDate *expireDate = [formatter dateFromString:self.liveEndTime];
|
|
|
+ NSTimeInterval timeInterval = [expireDate timeIntervalSinceDate:currentDate];
|
|
|
+ return self.expiredMinute * 60 + timeInterval;
|
|
|
+}
|
|
|
+
|
|
|
+- (void)dealloc {
|
|
|
+ if (_timeManager) {
|
|
|
+ [_timeManager stopDurationTimer];
|
|
|
+ }
|
|
|
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
|
+ if (_timer) {
|
|
|
+ dispatch_source_cancel(_timer);
|
|
|
+ _timer = nil;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+- (dispatch_source_t)timer {
|
|
|
+ if (!_timer) {
|
|
|
+ _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
|
|
|
+ uint64_t interval = (uint64_t)(10 * NSEC_PER_SEC);
|
|
|
+ dispatch_source_set_timer(_timer, DISPATCH_TIME_NOW, interval, 0);
|
|
|
+ MJWeakSelf;
|
|
|
+ dispatch_source_set_event_handler(_timer, ^{
|
|
|
+ dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
+ [weakSelf syncLikeCount];
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }
|
|
|
+ return _timer;
|
|
|
+}
|
|
|
+
|
|
|
+- (void)showAnimationView:(BOOL)isJoinRoom showMessag:(NSString *)message {
|
|
|
+ if (self.animationView && self.animationView.isShow) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ ANIMATIONTYPE type = isJoinRoom ? ANIMATIONTYPE_JOIN : ANIMATIONTYPE_RUSH;
|
|
|
+ self.animationView = [[LiveAnimationView alloc] initWithTitle:message animationType:type];
|
|
|
+ [self.view addSubview:self.animationView];
|
|
|
+ [self.animationView mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
+ make.left.right.mas_equalTo(self.view);
|
|
|
+ make.width.mas_equalTo(KPortraitWidth);
|
|
|
+ make.height.mas_equalTo(24.0f);
|
|
|
+ make.bottom.mas_equalTo(self.messageContentView.mas_top).offset(-6);
|
|
|
+ }];
|
|
|
+ [self.view bringSubviewToFront:self.animationView];
|
|
|
+ NSLog(@"------- start animation ");
|
|
|
+ MJWeakSelf;
|
|
|
+ [self.animationView startAnimationEndCallback:^{
|
|
|
+ NSLog(@"----- hide ");
|
|
|
+ weakSelf.animationView.isShow = YES;
|
|
|
+ weakSelf.animationView = nil;
|
|
|
+ }];
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+#pragma mark ---- 同步点赞数据
|
|
|
+
|
|
|
+- (void)syncLikeCount {
|
|
|
+ if (self.isOtherLogin) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ [KSNetworkingManager syncLikeRequest:KS_GET likeNum:self.likeCount roomUid:self.roomId success:^(NSDictionary * _Nonnull dic) {
|
|
|
+ if ([dic integerValueForKey:@"code"] == 200 && [dic boolValueForKey:@"status"]) {
|
|
|
+ [self notiferLikeStatusToAudience];
|
|
|
+ }
|
|
|
+ } faliure:^(NSError * _Nonnull error) {
|
|
|
+
|
|
|
+ }];
|
|
|
+}
|
|
|
+
|
|
|
+- (void)notiferLikeStatusToAudience {
|
|
|
+ RCChatroomLikeCount *likeCountMsg = [[RCChatroomLikeCount alloc] init];
|
|
|
+ likeCountMsg.count = self.likeCount;
|
|
|
+
|
|
|
+ [self sendMessage:likeCountMsg displayMessage:NO callback:^(BOOL success) {
|
|
|
+
|
|
|
+ }];
|
|
|
+}
|
|
|
/*
|
|
|
#pragma mark - Navigation
|
|
|
|