blob: 1316ea86392338c5990aa8c7aaec0975221de5ca [file] [log] [blame]
Alexandre Lisionc5148052015-03-04 15:10:35 -05001/*
Alexandre Lision9fe374b2016-01-06 10:17:31 -05002 * Copyright (C) 2015-2016 Savoir-faire Linux Inc.
Alexandre Lisionc5148052015-03-04 15:10:35 -05003 * Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Alexandre Lisionc5148052015-03-04 15:10:35 -050018 */
19#import "CurrentCallVC.h"
Kateryna Kostiuk00dcbff2019-07-11 15:42:13 -040020extern "C" {
21#import "libavutil/frame.h"
22#import "libavutil/display.h"
23}
Alexandre Lisionc5148052015-03-04 15:10:35 -050024
25#import <QuartzCore/QuartzCore.h>
26
Alexandre Lision210fe212016-01-27 11:15:13 -050027///Qt
28#import <QMimeData>
29#import <QtMacExtras/qmacfunctions.h>
30#import <QtCore/qabstractitemmodel.h>
Alexandre Lision210fe212016-01-27 11:15:13 -050031#import <QPixmap>
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -040032#import <QUrl>
Alexandre Lision210fe212016-01-27 11:15:13 -050033
34///LRC
Alexandre Lisionc5148052015-03-04 15:10:35 -050035#import <video/renderer.h>
Olivier Soldano994971f2017-12-05 16:30:12 -050036#import <api/newcallmodel.h>
37#import <api/call.h>
38#import <api/conversationmodel.h>
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -040039#import <api/avmodel.h>
Alexandre Lision210fe212016-01-27 11:15:13 -050040#import <globalinstances.h>
Alexandre Lisionc5148052015-03-04 15:10:35 -050041
Alexandre Lision62005312016-01-28 15:55:16 -050042#import "AppDelegate.h"
Alexandre Lisionf47a2562015-06-15 15:48:29 -040043#import "views/ITProgressIndicator.h"
Alexandre Lision74dd47f2015-04-14 13:47:42 -040044#import "views/CallView.h"
Kateryna Kostiuk81afce72018-10-30 16:40:50 -040045#import "views/NSColor+RingTheme.h"
Alexandre Lision210fe212016-01-27 11:15:13 -050046#import "delegates/ImageManipulationDelegate.h"
Alexandre Lision16d9c0a2015-08-10 12:05:15 -040047#import "ChatVC.h"
Alexandre Lision4baba4c2016-02-11 13:00:57 -050048#import "views/IconButton.h"
Anthony Léonard6f819752018-01-05 09:53:40 -050049#import "utils.h"
Kateryna Kostiuk00dcbff2019-07-11 15:42:13 -040050#import "views/CallMTKView.h"
Kateryna Kostiukc5fd3b92019-07-24 10:12:44 -040051#import "VideoCommon.h"
Kateryna Kostiuk88a6ee82019-09-10 17:55:08 -040052#import "views/GradientView.h"
Kateryna Kostiuk6891d4f2019-09-19 17:44:33 -040053#import "views/MovableView.h"
Kateryna Kostiuk06681682020-05-07 20:50:56 -040054#import "views/RenderingView.h"
Alexandre Lision74dd47f2015-04-14 13:47:42 -040055
Kateryna Kostiuk1ba5a012018-12-12 17:07:38 -050056@interface CurrentCallVC () <NSPopoverDelegate> {
Kateryna Kostiukc867eb92020-03-08 13:15:17 -040057 QString convUid_;
58 QString callUid_;
59 QString confUid_;
Olivier Soldano994971f2017-12-05 16:30:12 -050060 const lrc::api::account::Info *accountInfo_;
Anthony Léonard66a050c2018-01-03 16:32:34 -050061 NSTimer* refreshDurationTimer;
Olivier Soldano994971f2017-12-05 16:30:12 -050062}
Alexandre Lisionc5148052015-03-04 15:10:35 -050063
Alexandre Lision210fe212016-01-27 11:15:13 -050064// Main container
65@property (unsafe_unretained) IBOutlet NSSplitView* splitView;
Kateryna Kostiuk89398b62018-11-20 16:45:04 -050066@property (unsafe_unretained) IBOutlet NSView* backgroundImage;
Kateryna Kostiuk81afce72018-10-30 16:40:50 -040067@property (unsafe_unretained) IBOutlet NSBox* bluerBackgroundEffect;
Alexandre Lision210fe212016-01-27 11:15:13 -050068
Alexandre Lision89edc6a2015-11-09 11:30:47 -050069// Header info
70@property (unsafe_unretained) IBOutlet NSView* headerContainer;
Kateryna Kostiuk2aa39232019-10-10 11:55:11 -040071@property (unsafe_unretained) IBOutlet NSView* headerGradientView;
Alexandre Lision89edc6a2015-11-09 11:30:47 -050072@property (unsafe_unretained) IBOutlet NSTextField* timeSpentLabel;
73
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -040074// info
75@property (unsafe_unretained) IBOutlet NSStackView* infoContainer;
76@property (unsafe_unretained) IBOutlet NSImageView* contactPhoto;
77@property (unsafe_unretained) IBOutlet NSTextField* contactNameLabel;
78@property (unsafe_unretained) IBOutlet NSTextField* callStateLabel;
79@property (unsafe_unretained) IBOutlet NSTextField* contactIdLabel;
80@property (unsafe_unretained) IBOutlet IconButton* cancelCallButton;
81@property (unsafe_unretained) IBOutlet IconButton* pickUpButton;
82@property (unsafe_unretained) IBOutlet ITProgressIndicator *loadingIndicator;
Andreas Traczyk77a50d52018-05-08 17:47:31 -040083
Alexandre Lision89edc6a2015-11-09 11:30:47 -050084// Call Controls
Kateryna Kostiuk88a6ee82019-09-10 17:55:08 -040085@property (unsafe_unretained) IBOutlet GradientView* controlsPanel;
Kateryna Kostiuk2aa39232019-10-10 11:55:11 -040086@property (unsafe_unretained) IBOutlet NSStackView* controlsStackView;
Alexandre Lision62005312016-01-28 15:55:16 -050087
Alexandre Lision4baba4c2016-02-11 13:00:57 -050088@property (unsafe_unretained) IBOutlet IconButton* holdOnOffButton;
89@property (unsafe_unretained) IBOutlet IconButton* hangUpButton;
90@property (unsafe_unretained) IBOutlet IconButton* recordOnOffButton;
Alexandre Lision4baba4c2016-02-11 13:00:57 -050091@property (unsafe_unretained) IBOutlet IconButton* muteAudioButton;
92@property (unsafe_unretained) IBOutlet IconButton* muteVideoButton;
Alexandre Lision4baba4c2016-02-11 13:00:57 -050093@property (unsafe_unretained) IBOutlet IconButton* transferButton;
94@property (unsafe_unretained) IBOutlet IconButton* addParticipantButton;
95@property (unsafe_unretained) IBOutlet IconButton* chatButton;
Andreas Traczyk77a50d52018-05-08 17:47:31 -040096@property (unsafe_unretained) IBOutlet IconButton* qualityButton;
Alexandre Lisiond18fa272015-06-15 11:18:03 -040097
Alexandre Lisionc5148052015-03-04 15:10:35 -050098// Video
Alexandre Lision58cab672015-06-09 15:25:40 -040099@property (unsafe_unretained) IBOutlet CallView *videoView;
Kateryna Kostiuk06681682020-05-07 20:50:56 -0400100@property (unsafe_unretained) IBOutlet RenderingView *previewView;
Kateryna Kostiuk6891d4f2019-09-19 17:44:33 -0400101@property (unsafe_unretained) IBOutlet MovableView *movableBaseForView;
102@property (unsafe_unretained) IBOutlet NSView* hidePreviewBackground;
103@property (unsafe_unretained) IBOutlet NSButton* hidePreviewButton;
Kateryna Kostiuk00dcbff2019-07-11 15:42:13 -0400104
Kateryna Kostiuk06681682020-05-07 20:50:56 -0400105@property (unsafe_unretained) IBOutlet RenderingView *distantView;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500106
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400107@property RendererConnectionsHolder* renderConnections;
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400108@property QMetaObject::Connection videoStarted;
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400109@property QMetaObject::Connection callStateChanged;
Alexandre Lisionb65c0272015-07-22 15:51:29 -0400110@property QMetaObject::Connection messageConnection;
Kateryna Kostiuk133364b2018-10-31 11:36:08 -0400111@property QMetaObject::Connection profileUpdatedConnection;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500112
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400113//conference
114@property (unsafe_unretained) IBOutlet NSStackView *callingWidgetsContainer;
115
116@property (strong) NSPopover* brokerPopoverVC;
117
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400118@property (strong) IBOutlet ChatVC* chatVC;
119
Alexandre Lisionc5148052015-03-04 15:10:35 -0500120@end
121
122@implementation CurrentCallVC
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400123lrc::api::AVModel* mediaModel;
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400124NSMutableDictionary *connectingCalls;
Kateryna Kostiuk6891d4f2019-09-19 17:44:33 -0400125
126NSInteger const PREVIEW_WIDTH = 185;
127NSInteger const PREVIEW_HEIGHT = 130;
Kateryna Kostiuk2aa39232019-10-10 11:55:11 -0400128NSInteger const HIDE_PREVIEW_BUTTON_SIZE = 25;
Kateryna Kostiuk6891d4f2019-09-19 17:44:33 -0400129NSInteger const PREVIEW_MARGIN = 20;
130
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400131@synthesize holdOnOffButton, hangUpButton, recordOnOffButton, pickUpButton, chatButton, transferButton, addParticipantButton, timeSpentLabel, muteVideoButton, muteAudioButton, controlsPanel, headerContainer, videoView, previewView, splitView, loadingIndicator, backgroundImage, bluerBackgroundEffect, hidePreviewButton, hidePreviewBackground, movableBaseForView, infoContainer, contactPhoto, contactNameLabel, callStateLabel, contactIdLabel, cancelCallButton, headerGradientView, controlsStackView, callingWidgetsContainer, brokerPopoverVC;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500132
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400133@synthesize renderConnections;
Kateryna Kostiuk00dcbff2019-07-11 15:42:13 -0400134CVPixelBufferPoolRef pixelBufferPoolDistantView;
135CVPixelBufferRef pixelBufferDistantView;
136CVPixelBufferPoolRef pixelBufferPoolPreview;
137CVPixelBufferRef pixelBufferPreview;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500138
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400139/* update call and conversation info
140 * set info for chat view
141 * connect signals
142 */
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400143-(void) setCurrentCall:(const QString&)callUid
144 conversation:(const QString&)convUid
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400145 account:(const lrc::api::account::Info*)account
146 avModel:(lrc::api::AVModel *)avModel;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500147{
Olivier Soldano994971f2017-12-05 16:30:12 -0500148 if(account == nil)
149 return;
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400150
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400151 mediaModel = avModel;
Olivier Soldano994971f2017-12-05 16:30:12 -0500152 auto* callModel = account->callModel.get();
Alexandre Lisionc5148052015-03-04 15:10:35 -0500153
Olivier Soldano994971f2017-12-05 16:30:12 -0500154 if (not callModel->hasCall(callUid)){
155 callUid_.clear();
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400156 confUid_.clear();
Alexandre Lision2db8f472015-07-22 15:05:46 -0400157 return;
158 }
Olivier Soldano994971f2017-12-05 16:30:12 -0500159 callUid_ = callUid;
160 convUid_ = convUid;
161 accountInfo_ = account;
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400162 auto convIt = getConversationFromUid(convUid_, *accountInfo_->conversationModel);
163 confUid_ = convIt->confId;
Anthony Léonard4b0935f2017-12-26 12:05:22 -0500164 [self.chatVC setConversationUid:convUid model:account->conversationModel.get()];
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400165 [self connectSignals];
166}
167
168-(void) connectSignals {
169 auto* callModel = accountInfo_->callModel.get();
170 auto* convModel = accountInfo_->conversationModel.get();
171 //monitor for updated call state
172 QObject::disconnect(self.callStateChanged);
173 self.callStateChanged = QObject::connect(callModel,
174 &lrc::api::NewCallModel::callStatusChanged,
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400175 [self](const QString& callId) {
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400176 if ([self isCurrentCall: callId]) {
177 [self updateCall];
178 }
179 });
180 /* monitor media for messaging text messaging */
181 QObject::disconnect(self.messageConnection);
182 self.messageConnection = QObject::connect(convModel,
183 &lrc::api::ConversationModel::interactionStatusUpdated,
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400184 [self] (const QString& convUid,
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400185 uint64_t msgId,
186 lrc::api::interaction::Info msg) {
187 if (msg.type == lrc::api::interaction::Type::TEXT) {
188 if(not [[self splitView] isSubviewCollapsed:[[[self splitView] subviews] objectAtIndex: 1]]){
189 return;
190 }
191 [self uncollapseRightView];
192 }
193 });
194 //monitor for updated profile
195 QObject::disconnect(self.profileUpdatedConnection);
196 self.profileUpdatedConnection =
197 QObject::connect(accountInfo_->contactModel.get(),
198 &lrc::api::ContactModel::contactAdded,
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400199 [self](const QString &contactUri) {
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400200 auto convIt = getConversationFromUid(convUid_, *accountInfo_->conversationModel.get());
201 if (convIt == accountInfo_->conversationModel->allFilteredConversations().end()) {
202 return;
203 }
204 if (convIt->participants.empty()) {
205 return;
206
207 }
208 auto& contact = accountInfo_->contactModel->getContact(convIt->participants[0]);
209 if (contact.profileInfo.type == lrc::api::profile::Type::RING && contact.profileInfo.uri == contactUri)
210 accountInfo_->conversationModel->makePermanent(convUid_);
211 [contactPhoto setImage: [self getContactImageOfSize:120.0 withDefaultAvatar:YES]];
212 [self.delegate conversationInfoUpdatedFor:convUid_];
213 [self setBackground];
214 });
215 [self connectVideoSignals];
216}
217
218-(void) updatePendingCalls {
219 for (NSView *view in callingWidgetsContainer.subviews) {
220 view.removeFromSuperview;
221 }
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400222 NSDictionary * calls = connectingCalls[callUid_.toNSString()];
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400223 for (NSViewController * callView in calls.allValues) {
224 [self.callingWidgetsContainer addView: callView.view inGravity:NSStackViewGravityBottom];
225 }
Alexandre Lisionc5148052015-03-04 15:10:35 -0500226}
227
Kateryna Kostiuk88a6ee82019-09-10 17:55:08 -0400228-(void) setUpButtons:(lrc::api::call::Info&)callInfo isRecording:(BOOL) isRecording {
229 muteAudioButton.image = callInfo.audioMuted ? [NSImage imageNamed:@"ic_action_mute_audio.png"] :
230 [NSImage imageNamed:@"ic_action_audio.png"];
231 muteVideoButton.image = callInfo.videoMuted ? [NSImage imageNamed:@"ic_action_mute_video.png"] :
232 [NSImage imageNamed:@"ic_action_video.png"];
233 [muteVideoButton setHidden: callInfo.isAudioOnly ? YES: NO];
234 if (isRecording) {
235 [recordOnOffButton startBlinkAnimationfrom:[NSColor buttonBlinkColorColor] to:[NSColor whiteColor] scaleFactor: 1 duration: 1.5];
236 } else {
237 [recordOnOffButton stopBlinkAnimation];
238 }
239}
240
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400241- (void) setUpPreviewFrame {
Kateryna Kostiuk6891d4f2019-09-19 17:44:33 -0400242 CGPoint previewOrigin = CGPointMake(self.videoView.frame.size.width - PREVIEW_WIDTH - PREVIEW_MARGIN, PREVIEW_MARGIN);
243 movableBaseForView.frame = CGRectMake(previewOrigin.x, previewOrigin.y, PREVIEW_WIDTH, PREVIEW_HEIGHT);
Kateryna Kostiuk6891d4f2019-09-19 17:44:33 -0400244 self.movableBaseForView.movable = true;
245 previewView.frame = movableBaseForView.bounds;
Kateryna Kostiuk2aa39232019-10-10 11:55:11 -0400246 hidePreviewBackground.frame = [self frameForExpendPreviewButton];
Kateryna Kostiuke9eb38b2020-03-23 14:33:08 -0400247 if ([hidePreviewButton respondsToSelector:@selector(contentTintColor)]) {
248 hidePreviewButton.contentTintColor = [NSColor blackColor];
249 }
Kateryna Kostiuk6891d4f2019-09-19 17:44:33 -0400250}
251
Alexandre Lisionc5148052015-03-04 15:10:35 -0500252- (void)awakeFromNib
253{
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400254 [self.view setWantsLayer:YES];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500255
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400256 renderConnections = [[RendererConnectionsHolder alloc] init];
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400257
Alexandre Lisionf47a2562015-06-15 15:48:29 -0400258 [loadingIndicator setColor:[NSColor whiteColor]];
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400259 [loadingIndicator setNumberOfLines:200];
260 [loadingIndicator setWidthOfLine:4];
261 [loadingIndicator setLengthOfLine:4];
262 [loadingIndicator setInnerMargin:59];
Alexandre Lisionf47a2562015-06-15 15:48:29 -0400263
Alexandre Lisiona1eee3c2015-08-10 13:44:51 -0400264 [self.videoView setCallDelegate:self];
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400265 [bluerBackgroundEffect setWantsLayer:YES];
Kateryna Kostiuk89398b62018-11-20 16:45:04 -0500266 [backgroundImage setWantsLayer: YES];
267 backgroundImage.layer.contentsGravity = kCAGravityResizeAspectFill;
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400268 movableBaseForView.wantsLayer = YES;
Kateryna Kostiuk2aa39232019-10-10 11:55:11 -0400269 movableBaseForView.shadow = [[NSShadow alloc] init];
270 movableBaseForView.layer.shadowOpacity = 0.6;
271 movableBaseForView.layer.shadowColor = [[NSColor blackColor] CGColor];
272 movableBaseForView.layer.shadowOffset = NSMakeSize(0, -3);
273 movableBaseForView.layer.shadowRadius = 10;
274 previewView.wantsLayer = YES;
275 previewView.layer.cornerRadius = 5;
276 previewView.layer.masksToBounds = true;
277 hidePreviewBackground.wantsLayer = YES;
278 hidePreviewBackground.layer.cornerRadius = 5;
279 hidePreviewBackground.layer.maskedCorners = kCALayerMinXMinYCorner;
280 hidePreviewBackground.layer.masksToBounds = true;
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400281 movableBaseForView.hostingView = self.videoView;
282 [movableBaseForView setAutoresizingMask: NSViewNotSizable | NSViewMaxXMargin | NSViewMaxYMargin | NSViewMinXMargin | NSViewMinYMargin];
283 [previewView setAutoresizingMask: NSViewNotSizable | NSViewMaxXMargin | NSViewMaxYMargin | NSViewMinXMargin | NSViewMinYMargin];
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400284 connectingCalls = [[NSMutableDictionary alloc] init];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500285}
286
Anthony Léonard66a050c2018-01-03 16:32:34 -0500287-(void) updateDurationLabel
288{
289 if (accountInfo_ != nil) {
290 auto* callModel = accountInfo_->callModel.get();
291 if (callModel->hasCall(callUid_)) {
292 auto& callStatus = callModel->getCall(callUid_).status;
293 if (callStatus != lrc::api::call::Status::ENDED &&
294 callStatus != lrc::api::call::Status::TERMINATING &&
295 callStatus != lrc::api::call::Status::INVALID) {
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400296 [timeSpentLabel setStringValue:callModel->getFormattedCallDuration(callUid_).toNSString()];
Anthony Léonard66a050c2018-01-03 16:32:34 -0500297 return;
298 }
299 }
300 }
301
302 // If call is not running anymore or accountInfo_ is not set for any reason
303 // we stop the refresh loop
304 [refreshDurationTimer invalidate];
305 refreshDurationTimer = nil;
Anthony Léonard66a050c2018-01-03 16:32:34 -0500306}
307
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400308-(void) updateCall
Alexandre Lisionc5148052015-03-04 15:10:35 -0500309{
Olivier Soldano994971f2017-12-05 16:30:12 -0500310 if (accountInfo_ == nil)
311 return;
Alexandre Lisionbb5dbcd2015-07-09 16:36:47 -0400312
Olivier Soldano994971f2017-12-05 16:30:12 -0500313 auto* callModel = accountInfo_->callModel.get();
314 if (not callModel->hasCall(callUid_)) {
315 return;
316 }
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500317
Olivier Soldano994971f2017-12-05 16:30:12 -0500318 auto currentCall = callModel->getCall(callUid_);
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400319 NSLog(@"\n status %@ \n",lrc::api::call::to_string(currentCall.status).toNSString());
Anthony Léonard8ee26782018-01-05 10:23:04 -0500320 auto convIt = getConversationFromUid(convUid_, *accountInfo_->conversationModel);
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400321 if (convIt != accountInfo_->conversationModel->allFilteredConversations().end()) {
322 NSString* bestName = bestNameForConversation(*convIt, *accountInfo_->conversationModel);
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400323 [contactNameLabel setStringValue:bestName];
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400324 NSString* ringID = bestIDForConversation(*convIt, *accountInfo_->conversationModel);
325 if([bestName isEqualToString:ringID]) {
326 ringID = @"";
327 }
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400328 [contactIdLabel setStringValue:ringID];
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400329 }
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400330 [self setupContactInfo:contactPhoto];
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400331
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400332 confUid_ = convIt->confId;
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400333 [muteAudioButton setHidden:!confUid_.isEmpty()];
334 [muteVideoButton setHidden:!confUid_.isEmpty()];
335 [recordOnOffButton setHidden:!confUid_.isEmpty()];
336 [holdOnOffButton setHidden:!confUid_.isEmpty()];
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400337
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400338 [timeSpentLabel setStringValue:callModel->getFormattedCallDuration(callUid_).toNSString()];
Anthony Léonard66a050c2018-01-03 16:32:34 -0500339 if (refreshDurationTimer == nil)
340 refreshDurationTimer = [NSTimer scheduledTimerWithTimeInterval:1.0
341 target:self
342 selector:@selector(updateDurationLabel)
343 userInfo:nil
344 repeats:YES];
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400345 [self setBackground];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500346
Olivier Soldano994971f2017-12-05 16:30:12 -0500347 using Status = lrc::api::call::Status;
Kateryna Kostiuk88a6ee82019-09-10 17:55:08 -0400348 if (currentCall.status == Status::PAUSED) {
349 [holdOnOffButton startBlinkAnimationfrom:[NSColor buttonBlinkColorColor] to:[NSColor whiteColor] scaleFactor: 1.0 duration: 1.5];
350 } else {
351 [holdOnOffButton stopBlinkAnimation];
352 }
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400353
Kateryna Kostiuka7404812019-10-28 12:24:46 -0400354 [self setUpButtons: currentCall isRecording: (callModel->isRecording([self getcallID]) || mediaModel->getAlwaysRecord())];
355
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400356 [videoView setShouldAcceptInteractions: currentCall.status == Status::IN_PROGRESS];
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400357 callStateLabel.stringValue = currentCall.status == Status::INCOMING_RINGING ? @"wants to talk to you" : to_string(currentCall.status).toNSString();
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400358 loadingIndicator.hidden = (currentCall.status == Status::SEARCHING ||
359 currentCall.status == Status::CONNECTING ||
360 currentCall.status == Status::OUTGOING_RINGING) ? NO : YES;
361 pickUpButton.hidden = (currentCall.status == Status::INCOMING_RINGING) ? NO : YES;
362 callStateLabel.hidden = (currentCall.status == Status::IN_PROGRESS) ? YES : NO;
363 cancelCallButton.hidden = (currentCall.status == Status::IN_PROGRESS ||
364 currentCall.status == Status::PAUSED) ? YES : NO;
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400365 callingWidgetsContainer.hidden = (currentCall.status == Status::IN_PROGRESS) ? NO : YES;
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400366
Olivier Soldano994971f2017-12-05 16:30:12 -0500367 switch (currentCall.status) {
368 case Status::SEARCHING:
Olivier Soldano994971f2017-12-05 16:30:12 -0500369 case Status::CONNECTING:
Olivier Soldano994971f2017-12-05 16:30:12 -0500370 case Status::OUTGOING_RINGING:
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400371 case Status::INCOMING_RINGING:
372 [infoContainer setHidden: NO];
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400373 [headerContainer setHidden:YES];
Kateryna Kostiuk2aa39232019-10-10 11:55:11 -0400374 [headerGradientView setHidden:YES];
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400375 [controlsPanel setHidden:YES];
Kateryna Kostiuk2aa39232019-10-10 11:55:11 -0400376 [controlsStackView setHidden:YES];
Kateryna Kostiuk06681682020-05-07 20:50:56 -0400377 [self.distantView fillWithBlack];
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400378 [self.previewView fillWithBlack];
379 [hidePreviewBackground setHidden:YES];
380 [self.previewView setHidden: YES];
Kateryna Kostiuk06681682020-05-07 20:50:56 -0400381 [self.distantView setHidden: YES];
382 self.previewView.videoRunning = NO;
383 self.distantView.videoRunning = NO;
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400384 [backgroundImage setHidden:NO];
385 [bluerBackgroundEffect setHidden:NO];
Olivier Soldano994971f2017-12-05 16:30:12 -0500386 break;
Olivier Soldano994971f2017-12-05 16:30:12 -0500387 case Status::PAUSED:
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400388 [infoContainer setHidden: NO];
389 [headerContainer setHidden:NO];
Kateryna Kostiuk2aa39232019-10-10 11:55:11 -0400390 [headerGradientView setHidden:NO];
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400391 [controlsPanel setHidden:NO];
Kateryna Kostiuk2aa39232019-10-10 11:55:11 -0400392 [controlsStackView setHidden:NO];
Kateryna Kostiuk00dcbff2019-07-11 15:42:13 -0400393 [backgroundImage setHidden:NO];
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400394 [bluerBackgroundEffect setHidden:NO];
395 if(!currentCall.isAudioOnly) {
Kateryna Kostiuk06681682020-05-07 20:50:56 -0400396 [self.distantView fillWithBlack];
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400397 [self.previewView fillWithBlack];
398 [hidePreviewBackground setHidden:YES];
399 [self.previewView setHidden: YES];
Kateryna Kostiuk06681682020-05-07 20:50:56 -0400400 [self.distantView setHidden: YES];
401 self.previewView.videoRunning = NO;
402 self.distantView.videoRunning = NO;
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400403 }
Kateryna Kostiuk00dcbff2019-07-11 15:42:13 -0400404 break;
Olivier Soldano994971f2017-12-05 16:30:12 -0500405 case Status::INACTIVE:
Kateryna Kostiuk00dcbff2019-07-11 15:42:13 -0400406 if(currentCall.isAudioOnly) {
407 [self setUpAudioOnlyView];
408 } else {
409 [self setUpVideoCallView];
410 }
411 break;
Olivier Soldano994971f2017-12-05 16:30:12 -0500412 case Status::IN_PROGRESS:
“Kateryna”414738e2020-04-07 11:44:35 -0400413 callModel->setCurrentCall([self getcallID]);
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400414 [headerContainer setHidden:NO];
Kateryna Kostiuk2aa39232019-10-10 11:55:11 -0400415 [headerGradientView setHidden:NO];
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400416 [controlsPanel setHidden:NO];
Kateryna Kostiuk2aa39232019-10-10 11:55:11 -0400417 [controlsStackView setHidden:NO];
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400418 if(currentCall.isAudioOnly) {
419 [self setUpAudioOnlyView];
420 } else {
421 [self setUpVideoCallView];
422 }
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400423 break;
Olivier Soldano994971f2017-12-05 16:30:12 -0500424 case Status::CONNECTED:
Olivier Soldano994971f2017-12-05 16:30:12 -0500425 break;
426 case Status::ENDED:
427 case Status::TERMINATING:
428 case Status::INVALID:
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400429 case Status::PEER_BUSY:
430 case Status::TIMEOUT:
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400431 connectingCalls[callUid_.toNSString()] = nil;
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400432 //[self cleanUp];
433 [self.delegate callFinished];
Olivier Soldano994971f2017-12-05 16:30:12 -0500434 break;
435 }
Alexandre Lision4d9905e2016-01-22 12:01:36 -0500436}
437
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400438-(void) setUpVideoCallView {
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400439 [previewView fillWithBlack];
Kateryna Kostiuk06681682020-05-07 20:50:56 -0400440 [self.distantView fillWithBlack];
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400441 [previewView setHidden: NO];
Kateryna Kostiuk06681682020-05-07 20:50:56 -0400442 [self.distantView setHidden:NO];
443 [hidePreviewBackground setHidden: !self.previewView.videoRunning];
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400444 [bluerBackgroundEffect setHidden:YES];
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400445 [backgroundImage setHidden:YES];
Kateryna Kostiuk06681682020-05-07 20:50:56 -0400446 self.previewView.videoRunning = true;
447 self.distantView.videoRunning = true;
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400448}
449
450-(void) setUpAudioOnlyView {
Kateryna Kostiuk00dcbff2019-07-11 15:42:13 -0400451 [self.previewView setHidden: YES];
Kateryna Kostiuk06681682020-05-07 20:50:56 -0400452 [self.distantView setHidden: YES];
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400453 [hidePreviewBackground setHidden: YES];
454 [bluerBackgroundEffect setHidden:NO];
455 [backgroundImage setHidden:NO];
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400456}
457
458-(void) setBackground {
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400459 auto* convModel = accountInfo_->conversationModel.get();
460 auto it = getConversationFromUid(convUid_, *convModel);
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400461 NSImage *image= [self getContactImageOfSize:120.0 withDefaultAvatar:NO];
462 if(image) {
Kateryna Kostiuk89398b62018-11-20 16:45:04 -0500463 CIImage * ciImage = [[CIImage alloc] initWithData:[image TIFFRepresentation]];
464 CIContext *context = [[CIContext alloc] init];
465 CIFilter *clamp = [CIFilter filterWithName:@"CIAffineClamp"];
466 [clamp setValue:[NSAffineTransform transform] forKey:@"inputTransform"];
467 [clamp setValue:ciImage forKey: kCIInputImageKey];
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400468 CIFilter* bluerFilter = [CIFilter filterWithName:@"CIGaussianBlur"];
469 [bluerFilter setDefaults];
Kateryna Kostiuk89398b62018-11-20 16:45:04 -0500470 [bluerFilter setValue:[NSNumber numberWithFloat: 9] forKey:@"inputRadius"];
471 [bluerFilter setValue:[clamp valueForKey:kCIOutputImageKey] forKey: kCIInputImageKey];
472 CIImage *result = [bluerFilter valueForKey:kCIOutputImageKey];
473 CGRect extent = [result extent];
474 CGImageRef cgImage = [context createCGImage:result fromRect: [ciImage extent]];
475 NSImage *bluredImage = [[NSImage alloc] initWithCGImage:cgImage size:NSSizeFromCGSize(CGSizeMake(image.size.width, image.size.height))];
476 backgroundImage.layer.contents = bluredImage;
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400477 [backgroundImage setHidden:NO];
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400478 [bluerBackgroundEffect setFillColor:[NSColor darkGrayColor]];
479 [bluerBackgroundEffect setAlphaValue:0.6];
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400480 } else {
Kateryna Kostiuk2aa39232019-10-10 11:55:11 -0400481 contactNameLabel.textColor = [NSColor textColor];
Kateryna Kostiuk2aa39232019-10-10 11:55:11 -0400482 contactIdLabel.textColor = [NSColor textColor];
483 callStateLabel.textColor = [NSColor textColor];
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400484 backgroundImage.layer.contents = nil;
Kateryna Kostiuk2aa39232019-10-10 11:55:11 -0400485 [bluerBackgroundEffect setFillColor:[NSColor windowBackgroundColor]];
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400486 [bluerBackgroundEffect setAlphaValue:1];
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400487 [backgroundImage setHidden:YES];
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400488 }
489}
490
Kateryna Kostiuk133364b2018-10-31 11:36:08 -0400491-(NSImage *) getContactImageOfSize: (double) size withDefaultAvatar:(BOOL) shouldDrawDefault {
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400492 auto* convModel = accountInfo_->conversationModel.get();
493 auto convIt = getConversationFromUid(convUid_, *convModel);
494 if (convIt == convModel->allFilteredConversations().end()) {
495 return nil;
496 }
497 if(shouldDrawDefault) {
498 auto& imgManip = reinterpret_cast<Interfaces::ImageManipulationDelegate&>(GlobalInstances::pixmapManipulator());
499 QVariant photo = imgManip.conversationPhoto(*convIt, *accountInfo_, QSize(size, size), NO);
500 return QtMac::toNSImage(qvariant_cast<QPixmap>(photo));
501 }
502 auto contact = accountInfo_->contactModel->getContact(convIt->participants[0]);
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400503 NSData *imageData = [[NSData alloc] initWithBase64EncodedString:contact.profileInfo.avatar.toNSString() options:NSDataBase64DecodingIgnoreUnknownCharacters];
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400504 return [[NSImage alloc] initWithData:imageData];
505}
506
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400507-(void) setupContactInfo:(NSImageView*)imageView
508{
509 [imageView setImage: [self getContactImageOfSize:120.0 withDefaultAvatar:YES]];
510}
511
Olivier Soldano994971f2017-12-05 16:30:12 -0500512-(void)collapseRightView
513{
514 NSView *right = [[splitView subviews] objectAtIndex:1];
515 NSView *left = [[splitView subviews] objectAtIndex:0];
516 NSRect leftFrame = [left frame];
517 [right setHidden:YES];
518 [splitView display];
519}
520
Alexandre Lisionc5148052015-03-04 15:10:35 -0500521-(void) connectVideoSignals
522{
Olivier Soldano994971f2017-12-05 16:30:12 -0500523 if (accountInfo_ == nil)
524 return;
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400525 [self connectRenderer];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500526}
527
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400528-(void) connectRenderer
Alexandre Lisionc5148052015-03-04 15:10:35 -0500529{
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400530 QObject::disconnect(renderConnections.frameUpdated);
531 QObject::disconnect(renderConnections.stopped);
532 QObject::disconnect(renderConnections.started);
533 renderConnections.started =
534 QObject::connect(mediaModel,
535 &lrc::api::AVModel::rendererStarted,
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400536 [=](const QString& id) {
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400537 if (id == lrc::api::video::PREVIEW_RENDERER_ID) {
538 [self.previewView setHidden:NO];
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400539 [hidePreviewBackground setHidden: NO];
Kateryna Kostiuk06681682020-05-07 20:50:56 -0400540 self.previewView.videoRunning = true;
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400541 } else if ([self isCurrentCall: id]) {
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400542 [self mouseIsMoving: NO];
Kateryna Kostiuk06681682020-05-07 20:50:56 -0400543 self.distantView.videoRunning = true;
544 [self.distantView setHidden:NO];
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400545 [bluerBackgroundEffect setHidden:YES];
546 [backgroundImage setHidden:YES];
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400547 }
Alexandre Lisionc5148052015-03-04 15:10:35 -0500548 });
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400549 renderConnections.stopped =
550 QObject::connect(mediaModel,
551 &lrc::api::AVModel::rendererStopped,
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400552 [=](const QString& id) {
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400553 if (id == lrc::api::video::PREVIEW_RENDERER_ID) {
554 [self.previewView setHidden:YES];
Kateryna Kostiuk06681682020-05-07 20:50:56 -0400555 self.previewView.videoRunning = false;
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400556 } else if ([self isCurrentCall: id]) {
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400557 [self mouseIsMoving: YES];
Kateryna Kostiuk06681682020-05-07 20:50:56 -0400558 self.distantView.videoRunning = false;
559 [self.distantView setHidden:YES];
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400560 [bluerBackgroundEffect setHidden:NO];
561 [backgroundImage setHidden:NO];
Kateryna Kostiuk00dcbff2019-07-11 15:42:13 -0400562 }
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400563 });
564 renderConnections.frameUpdated =
565 QObject::connect(mediaModel,
566 &lrc::api::AVModel::frameUpdated,
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400567 [=](const QString& id) {
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400568 if (id == lrc::api::video::PREVIEW_RENDERER_ID) {
569 auto renderer = &mediaModel->getRenderer(lrc::api::video::PREVIEW_RENDERER_ID);
570 if(!renderer->isRendering()) {
571 return;
572 }
Kateryna Kostiuk06681682020-05-07 20:50:56 -0400573 [hidePreviewBackground setHidden: !self.previewView.videoRunning];
574 [self rendererPreview: renderer];
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400575 } else if ([self isCurrentCall: id]) {
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400576 auto renderer = &mediaModel->getRenderer(id);
577 if(!renderer->isRendering()) {
578 return;
579 }
Kateryna Kostiuk06681682020-05-07 20:50:56 -0400580 [self rendererDistantView: renderer];
Kateryna Kostiuk732b4062018-11-28 09:59:28 -0500581 }
Alexandre Lisionc5148052015-03-04 15:10:35 -0500582 });
583}
584
Kateryna Kostiuk06681682020-05-07 20:50:56 -0400585-(void) rendererDistantView: (const lrc::api::video::Renderer*)renderer {
Kateryna Kostiuk00dcbff2019-07-11 15:42:13 -0400586 @autoreleasepool {
587 auto framePtr = renderer->currentAVFrame();
588 auto frame = framePtr.get();
589 if(!frame || !frame->width || !frame->height) {
590 return;
591 }
592 auto frameSize = CGSizeMake(frame->width, frame->height);
593 auto rotation = 0;
594 if (auto matrix = av_frame_get_side_data(frame, AV_FRAME_DATA_DISPLAYMATRIX)) {
595 const int32_t* data = reinterpret_cast<int32_t*>(matrix->data);
596 rotation = av_display_rotation_get(data);
597 }
598 if (frame->data[3] != NULL && (CVPixelBufferRef)frame->data[3]) {
Kateryna Kostiuk06681682020-05-07 20:50:56 -0400599 [self.distantView renderWithPixelBuffer: (CVPixelBufferRef)frame->data[3]
Kateryna Kostiuk00dcbff2019-07-11 15:42:13 -0400600 size: frameSize
601 rotation: rotation
602 fillFrame: false];
603 }
604 if (CVPixelBufferRef pixelBuffer = [self getBufferForDistantViewFromFrame:frame]) {
Kateryna Kostiuk06681682020-05-07 20:50:56 -0400605 [self.distantView renderWithPixelBuffer: pixelBuffer
Kateryna Kostiuk00dcbff2019-07-11 15:42:13 -0400606 size: frameSize
607 rotation: rotation
608 fillFrame: false];
609 }
Kateryna Kostiukbcf24e92018-11-20 10:09:06 -0500610 }
Anthony Léonard14e7bf32017-06-08 08:13:16 -0400611}
612
Kateryna Kostiuk06681682020-05-07 20:50:56 -0400613-(void) rendererPreview: (const lrc::api::video::Renderer*)renderer {
614 @autoreleasepool {
615 auto framePtr = renderer->currentAVFrame();
616 auto frame = framePtr.get();
617 if(!frame || !frame->width || !frame->height) {
618 return;
619 }
620 auto frameSize = CGSizeMake(frame->width, frame->height);
621 auto rotation = 0;
622 if (auto matrix = av_frame_get_side_data(frame, AV_FRAME_DATA_DISPLAYMATRIX)) {
623 const int32_t* data = reinterpret_cast<int32_t*>(matrix->data);
624 rotation = av_display_rotation_get(data);
625 }
626 if (frame->data[3] != NULL && (CVPixelBufferRef)frame->data[3]) {
627 [self.previewView renderWithPixelBuffer: (CVPixelBufferRef)frame->data[3]
628 size: frameSize
629 rotation: rotation
630 fillFrame: false];
631 }
632 if (CVPixelBufferRef pixelBuffer = [self getBufferForPreviewFromFrame:frame]) {
633 [self.previewView renderWithPixelBuffer: pixelBuffer
634 size: frameSize
635 rotation: rotation
636 fillFrame: true];
637 }
638 }
639}
640
Kateryna Kostiuk00dcbff2019-07-11 15:42:13 -0400641-(CVPixelBufferRef) getBufferForPreviewFromFrame:(const AVFrame*)frame {
Kateryna Kostiukc5fd3b92019-07-24 10:12:44 -0400642 [VideoCommon fillPixelBuffr:&pixelBufferPreview fromFrame:frame bufferPool:&pixelBufferPoolPreview];
643 CVPixelBufferRef buffer = pixelBufferPreview;
644 return buffer;
Kateryna Kostiuk00dcbff2019-07-11 15:42:13 -0400645}
646
647-(CVPixelBufferRef) getBufferForDistantViewFromFrame:(const AVFrame*)frame {
Kateryna Kostiukc5fd3b92019-07-24 10:12:44 -0400648 [VideoCommon fillPixelBuffr:&pixelBufferDistantView fromFrame:frame bufferPool:&pixelBufferPoolDistantView];
649 CVPixelBufferRef buffer = pixelBufferDistantView;
650 return buffer;
Kateryna Kostiuk00dcbff2019-07-11 15:42:13 -0400651}
652
Alexandre Lisionc5148052015-03-04 15:10:35 -0500653- (void) initFrame
654{
655 [self.view setFrame:self.view.superview.bounds];
656 [self.view setHidden:YES];
657 self.view.layer.position = self.view.frame.origin;
Alexandre Lisionbb5dbcd2015-07-09 16:36:47 -0400658 [self collapseRightView];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500659}
660
661# pragma private IN/OUT animations
662
Olivier Soldano994971f2017-12-05 16:30:12 -0500663-(void)uncollapseRightView
664{
665 NSView *left = [[splitView subviews] objectAtIndex:0];
666 NSView *right = [[splitView subviews] objectAtIndex:1];
667 [right setHidden:NO];
668
669 CGFloat dividerThickness = [splitView dividerThickness];
670
671 // get the different frames
672 NSRect leftFrame = [left frame];
673 NSRect rightFrame = [right frame];
674
675 leftFrame.size.width = (leftFrame.size.width - rightFrame.size.width - dividerThickness);
676 rightFrame.origin.x = leftFrame.size.width + dividerThickness;
677 [left setFrameSize:leftFrame.size];
678 [right setFrame:rightFrame];
679 [splitView display];
680
681 [self.chatVC takeFocus];
682}
683
Alexandre Lisionc5148052015-03-04 15:10:35 -0500684-(void) cleanUp
685{
Anthony Léonard5c287642018-02-21 15:54:19 -0500686 if(self.splitView.isInFullScreenMode)
687 [self.splitView exitFullScreenModeWithOptions:nil];
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400688 QObject::disconnect(renderConnections.frameUpdated);
689 QObject::disconnect(renderConnections.started);
690 QObject::disconnect(renderConnections.stopped);
Anthony Léonardc0013bb2018-02-20 16:23:02 -0500691 QObject::disconnect(self.messageConnection);
Alexandre Lision883719f2015-10-22 17:37:45 -0400692
Alexandre Lision4baba4c2016-02-11 13:00:57 -0500693 [self.chatButton setPressed:NO];
Alexandre Lision883719f2015-10-22 17:37:45 -0400694 [self collapseRightView];
Alexandre Lision57227772016-01-15 17:19:36 -0500695
Alexandre Lision57227772016-01-15 17:19:36 -0500696 [timeSpentLabel setStringValue:@""];
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400697 [contactIdLabel setStringValue:@""];
698 [contactNameLabel setStringValue:@""];
699 [contactPhoto setImage:nil];
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400700 //background view
701 [bluerBackgroundEffect setHidden:NO];
702 [backgroundImage setHidden:NO];
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400703 backgroundImage.layer.contents = nil;
Kateryna Kostiuk00dcbff2019-07-11 15:42:13 -0400704 [self.previewView setHidden:YES];
Kateryna Kostiuk06681682020-05-07 20:50:56 -0400705 [self.distantView setHidden:YES];
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400706
707 contactNameLabel.textColor = [NSColor highlightColor];
708 contactNameLabel.textColor = [NSColor highlightColor];
709 contactIdLabel.textColor = [NSColor highlightColor];
710 callStateLabel.textColor = [NSColor highlightColor];
Kateryna Kostiuk5acaefd2020-03-25 11:14:25 -0400711 [self.chatVC clearData];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500712}
713
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400714/*
715 * update ui
716*/
717
Andreas Traczykecdc4fa2018-03-22 16:11:47 -0400718-(void) setupCallView
719{
720 if (accountInfo_ == nil)
721 return;
722
723 auto* callModel = accountInfo_->callModel.get();
Andreas Traczykecdc4fa2018-03-22 16:11:47 -0400724
Andreas Traczykecdc4fa2018-03-22 16:11:47 -0400725 /* check if text media is already present */
726 if(not callModel->hasCall(callUid_))
727 return;
728
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400729 // when call comes in we want to show the controls/header
730 [self mouseIsMoving: YES];
Andreas Traczykecdc4fa2018-03-22 16:11:47 -0400731 [loadingIndicator setAnimates:YES];
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400732 auto currentCall = callModel->getCall([self getcallID]);
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400733 [previewView setHidden: YES];
734 [self setUpPreviewFrame];
735 [self updatePendingCalls];
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400736 [self updateCall];
Andreas Traczykecdc4fa2018-03-22 16:11:47 -0400737}
738
739-(void) showWithAnimation:(BOOL)animate
740{
741 if (!animate) {
742 [self.view setHidden:NO];
743 [self setupCallView];
744 return;
745 }
746
747 CGRect frame = CGRectOffset(self.view.superview.bounds, -self.view.superview.bounds.size.width, 0);
748 [self.view setHidden:NO];
749
750 [CATransaction begin];
751 CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
752 [animation setFromValue:[NSValue valueWithPoint:frame.origin]];
753 [animation setToValue:[NSValue valueWithPoint:self.view.superview.bounds.origin]];
754 [animation setDuration:0.2f];
755 [animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]];
756 [CATransaction setCompletionBlock:^{
757 [self setupCallView];
758 }];
759
760 [self.view.layer addAnimation:animation forKey:animation.keyPath];
761 [CATransaction commit];
762}
763
764-(void) hideWithAnimation:(BOOL)animate
Alexandre Lisionc5148052015-03-04 15:10:35 -0500765{
Alexandre Lisionc5148052015-03-04 15:10:35 -0500766 if(self.view.frame.origin.x < 0) {
Alexandre Lisionc5148052015-03-04 15:10:35 -0500767 return;
768 }
769
Andreas Traczykecdc4fa2018-03-22 16:11:47 -0400770 if (!animate) {
771 [self.view setHidden:YES];
772 return;
773 }
774
Alexandre Lisionc5148052015-03-04 15:10:35 -0500775 CGRect frame = CGRectOffset(self.view.frame, -self.view.frame.size.width, 0);
776 [CATransaction begin];
777 CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
778 [animation setFromValue:[NSValue valueWithPoint:self.view.frame.origin]];
779 [animation setToValue:[NSValue valueWithPoint:frame.origin]];
780 [animation setDuration:0.2f];
Alexandre Lision22d615b2016-01-25 12:54:34 -0500781 [animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500782
783 [CATransaction setCompletionBlock:^{
784 [self.view setHidden:YES];
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400785 // first make sure everything is disconnected
Alexandre Lisionc5148052015-03-04 15:10:35 -0500786 [self cleanUp];
Olivier Soldano994971f2017-12-05 16:30:12 -0500787// if (currentCall_) {
788// [self animateIn];
789// }
Alexandre Lisionc5148052015-03-04 15:10:35 -0500790 }];
791 [self.view.layer addAnimation:animation forKey:animation.keyPath];
Alexandre Lisiona1c6d752015-06-23 12:27:38 -0400792
793 [self.view.layer setPosition:frame.origin];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500794 [CATransaction commit];
795}
796
797/**
798 * Debug purpose
799 */
800-(void) dumpFrame:(CGRect) frame WithName:(NSString*) name
801{
802 NSLog(@"frame %@ : %f %f %f %f \n\n",name ,frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
803}
804
Alexandre Lision58cab672015-06-09 15:25:40 -0400805#pragma mark - Button methods
806
Alexandre Lisionc5148052015-03-04 15:10:35 -0500807- (IBAction)hangUp:(id)sender {
Olivier Soldano994971f2017-12-05 16:30:12 -0500808 if (accountInfo_ == nil)
809 return;
810
811 auto* callModel = accountInfo_->callModel.get();
Kateryna Kostiuk28b99be2019-11-18 14:54:08 -0500812 callModel->hangUp(callUid_);
Alexandre Lisionc5148052015-03-04 15:10:35 -0500813}
814
815- (IBAction)accept:(id)sender {
Olivier Soldano994971f2017-12-05 16:30:12 -0500816 if (accountInfo_ == nil)
817 return;
818
Anthony Léonardf584cc52018-01-19 12:00:19 -0500819 // If we accept a conversation with a non trusted contact, we first accept it
820 auto convIt = getConversationFromUid(convUid_, *accountInfo_->conversationModel.get());
821 if (convIt != accountInfo_->conversationModel->allFilteredConversations().end()) {
822 auto& contact = accountInfo_->contactModel->getContact(convIt->participants[0]);
823 if (contact.profileInfo.type == lrc::api::profile::Type::PENDING)
824 accountInfo_->conversationModel->makePermanent(convUid_);
825 }
826
Olivier Soldano994971f2017-12-05 16:30:12 -0500827 auto* callModel = accountInfo_->callModel.get();
828
829 callModel->accept(callUid_);
Alexandre Lisionc5148052015-03-04 15:10:35 -0500830}
831
832- (IBAction)toggleRecording:(id)sender {
Olivier Soldano994971f2017-12-05 16:30:12 -0500833 if (accountInfo_ == nil)
834 return;
835
836 auto* callModel = accountInfo_->callModel.get();
Olivier Soldano994971f2017-12-05 16:30:12 -0500837 callModel->toggleAudioRecord(callUid_);
Kateryna Kostiuk88a6ee82019-09-10 17:55:08 -0400838 if (callModel->isRecording(callUid_)) {
839 [recordOnOffButton startBlinkAnimationfrom:[NSColor buttonBlinkColorColor] to:[NSColor whiteColor] scaleFactor: 1 duration: 1.5];
840 } else {
841 [recordOnOffButton stopBlinkAnimation];
842 }
Alexandre Lisionc5148052015-03-04 15:10:35 -0500843}
844
845- (IBAction)toggleHold:(id)sender {
Olivier Soldano994971f2017-12-05 16:30:12 -0500846 if (accountInfo_ == nil)
847 return;
848
849 auto* callModel = accountInfo_->callModel.get();
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400850 callModel->togglePause([self getcallID]);
Alexandre Lisionc5148052015-03-04 15:10:35 -0500851}
852
Alexandre Lision62005312016-01-28 15:55:16 -0500853- (IBAction)showDialpad:(id)sender {
854 AppDelegate* appDelegate = (AppDelegate *)[[NSApplication sharedApplication] delegate];
855 [appDelegate showDialpad];
856}
857
Alexandre Lision58cab672015-06-09 15:25:40 -0400858-(IBAction)toggleChat:(id)sender;
859{
860 BOOL rightViewCollapsed = [[self splitView] isSubviewCollapsed:[[[self splitView] subviews] objectAtIndex: 1]];
861 if (rightViewCollapsed) {
862 [self uncollapseRightView];
Alexandre Lision58cab672015-06-09 15:25:40 -0400863 } else {
864 [self collapseRightView];
865 }
Alexandre Lision62005312016-01-28 15:55:16 -0500866 [chatButton setPressed:rightViewCollapsed];
Alexandre Lision58cab672015-06-09 15:25:40 -0400867}
868
Alexandre Lisiond18fa272015-06-15 11:18:03 -0400869- (IBAction)muteAudio:(id)sender
870{
Olivier Soldano994971f2017-12-05 16:30:12 -0500871 if (accountInfo_ == nil)
872 return;
873
874 auto* callModel = accountInfo_->callModel.get();
Kateryna Kostiuk54d76972018-06-07 15:45:07 -0400875 auto currentCall = callModel->getCall(callUid_);
876 if (currentCall.audioMuted) {
877 muteAudioButton.image = [NSImage imageNamed:@"ic_action_audio.png"];
878 } else {
879 muteAudioButton.image = [NSImage imageNamed:@"ic_action_mute_audio.png"];
880 }
Olivier Soldano994971f2017-12-05 16:30:12 -0500881 callModel->toggleMedia(callUid_, lrc::api::NewCallModel::Media::AUDIO);
Alexandre Lisiond18fa272015-06-15 11:18:03 -0400882}
883
884- (IBAction)muteVideo:(id)sender
885{
Olivier Soldano994971f2017-12-05 16:30:12 -0500886 if (accountInfo_ == nil)
887 return;
Olivier Soldano994971f2017-12-05 16:30:12 -0500888 auto* callModel = accountInfo_->callModel.get();
Kateryna Kostiuk54d76972018-06-07 15:45:07 -0400889 auto currentCall = callModel->getCall(callUid_);
890 if(!currentCall.isAudioOnly) {
891 if (currentCall.videoMuted) {
892 muteVideoButton.image = [NSImage imageNamed:@"ic_action_video.png"];
893 } else {
894 muteVideoButton.image = [NSImage imageNamed:@"ic_action_mute_video.png"];
895 }
896 }
Olivier Soldano994971f2017-12-05 16:30:12 -0500897 callModel->toggleMedia(callUid_, lrc::api::NewCallModel::Media::VIDEO);
Alexandre Lisiond18fa272015-06-15 11:18:03 -0400898}
Alexandre Lision883719f2015-10-22 17:37:45 -0400899
900- (IBAction)toggleTransferView:(id)sender {
Kateryna Kostiuk1ba5a012018-12-12 17:07:38 -0500901
Alexandre Lisionf23ec5a2015-07-16 11:24:06 -0400902}
Alexandre Lisiond18fa272015-06-15 11:18:03 -0400903
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500904- (IBAction)toggleAddParticipantView:(id)sender {
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400905 if (brokerPopoverVC != nullptr) {
906 [brokerPopoverVC performClose:self];
907 brokerPopoverVC = NULL;
908 } else {
909 auto* contactSelectorVC = [[ChooseContactVC alloc] initWithNibName:@"ChooseContactVC" bundle:nil];
910 auto* convModel = accountInfo_->conversationModel.get();
911 [contactSelectorVC setConversationModel:convModel andCurrentConversation: convUid_];
912 contactSelectorVC.delegate = self;
913 brokerPopoverVC = [[NSPopover alloc] init];
914 [brokerPopoverVC setContentSize:contactSelectorVC.view.frame.size];
915 [brokerPopoverVC setContentViewController:contactSelectorVC];
916 [brokerPopoverVC setAnimates:YES];
917 [brokerPopoverVC setBehavior:NSPopoverBehaviorTransient];
918 [brokerPopoverVC setDelegate:self];
919 [brokerPopoverVC showRelativeToRect:[sender bounds] ofView:sender preferredEdge:NSMinYEdge];
920 }
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500921}
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400922
Kateryna Kostiuk6891d4f2019-09-19 17:44:33 -0400923- (IBAction)hidePreview:(id)sender {
924 CGRect previewFrame = previewView.frame;
Kateryna Kostiuk28b99be2019-11-18 14:54:08 -0500925 CGRect newPreviewFrame;
Kateryna Kostiuk2aa39232019-10-10 11:55:11 -0400926 if (previewFrame.size.width > HIDE_PREVIEW_BUTTON_SIZE) {
Kateryna Kostiuk6891d4f2019-09-19 17:44:33 -0400927 self.movableBaseForView.movable = false;
928 newPreviewFrame = self.getVideoPreviewCollapsedSize;
Kateryna Kostiuk6891d4f2019-09-19 17:44:33 -0400929 hidePreviewButton.image = [NSImage imageNamed: NSImageNameTouchBarEnterFullScreenTemplate];
930 } else {
931 self.movableBaseForView.movable = true;
932 newPreviewFrame = CGRectMake(0, 0, PREVIEW_WIDTH, PREVIEW_HEIGHT);
Kateryna Kostiuk6891d4f2019-09-19 17:44:33 -0400933 hidePreviewButton.image = [NSImage imageNamed: NSImageNameTouchBarExitFullScreenTemplate];
934 }
935 [NSAnimationContext runAnimationGroup:^(NSAnimationContext * _Nonnull context) {
936 context.duration = 0.2f;
937 context.timingFunction = [CAMediaTimingFunction functionWithName: kCAMediaTimingFunctionEaseOut];
938 previewView.animator.frame = newPreviewFrame;
939 } completionHandler: nil];
Kateryna Kostiuk6891d4f2019-09-19 17:44:33 -0400940}
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500941
Alexandre Lision58cab672015-06-09 15:25:40 -0400942#pragma mark - NSSplitViewDelegate
943
944/* Return YES if the subview should be collapsed because the user has double-clicked on an adjacent divider. If a split view has a delegate, and the delegate responds to this message, it will be sent once for the subview before a divider when the user double-clicks on that divider, and again for the subview after the divider, but only if the delegate returned YES when sent -splitView:canCollapseSubview: for the subview in question. When the delegate indicates that both subviews should be collapsed NSSplitView's behavior is undefined.
945 */
946- (BOOL)splitView:(NSSplitView *)splitView shouldCollapseSubview:(NSView *)subview forDoubleClickOnDividerAtIndex:(NSInteger)dividerIndex;
947{
948 NSView* rightView = [[splitView subviews] objectAtIndex:1];
949 return ([subview isEqual:rightView]);
950}
951
952
953- (BOOL)splitView:(NSSplitView *)splitView canCollapseSubview:(NSView *)subview;
954{
955 NSView* rightView = [[splitView subviews] objectAtIndex:1];
956 return ([subview isEqual:rightView]);
957}
958
959
Alexandre Lisiona1eee3c2015-08-10 13:44:51 -0400960# pragma mark - CallnDelegate
Alexandre Lision58cab672015-06-09 15:25:40 -0400961
962- (void) callShouldToggleFullScreen
963{
964 if(self.splitView.isInFullScreenMode)
965 [self.splitView exitFullScreenModeWithOptions:nil];
966 else {
967 NSApplicationPresentationOptions options = NSApplicationPresentationDefault +NSApplicationPresentationAutoHideDock +
968 NSApplicationPresentationAutoHideMenuBar + NSApplicationPresentationAutoHideToolbar;
969 NSDictionary *opts = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithUnsignedInt:options],
970 NSFullScreenModeApplicationPresentationOptions, nil];
971
972 [self.splitView enterFullScreenMode:[NSScreen mainScreen] withOptions:opts];
973 }
974}
975
Alexandre Lisiona1eee3c2015-08-10 13:44:51 -0400976-(void) mouseIsMoving:(BOOL) move
977{
Kateryna Kostiuk2aa39232019-10-10 11:55:11 -0400978 [[controlsPanel animator] setAlphaValue:move];// fade out
979 [[controlsStackView animator] setAlphaValue:move];
Alexandre Lisiona1eee3c2015-08-10 13:44:51 -0400980 [[headerContainer animator] setAlphaValue:move];
Kateryna Kostiuk2aa39232019-10-10 11:55:11 -0400981 [[headerGradientView animator] setAlphaValue:move];
Alexandre Lisiona1eee3c2015-08-10 13:44:51 -0400982}
983
Kateryna Kostiuk89398b62018-11-20 16:45:04 -0500984- (BOOL)splitView:(NSSplitView *)splitView shouldHideDividerAtIndex:(NSInteger)dividerIndex
985{
986 return YES;
987}
988
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400989-(void) screenShare {
990 NSScreen *mainScreen = [NSScreen mainScreen];
991 NSRect screenFrame = mainScreen.frame;
992 QRect captureRect = QRect(screenFrame.origin.x, screenFrame.origin.y, screenFrame.size.width, screenFrame.size.height);
993 mediaModel->setDisplay(0, screenFrame.origin.x, screenFrame.origin.y, screenFrame.size.width, screenFrame.size.height);
994}
995-(void) switchToDevice:(int)deviceID {
996 auto devices = mediaModel->getDevices();
997 auto device = devices[deviceID];
998 mediaModel->switchInputTo(device);
999}
1000
Kateryna Kostiukc867eb92020-03-08 13:15:17 -04001001-(QVector<QString>) getDeviceList {
1002 QVector<QString> devicesVector;
Kateryna Kostiuk64533102019-10-29 15:34:29 -04001003 for (auto device : mediaModel->getDevices()) {
1004 try {
1005 auto settings = mediaModel->getDeviceSettings(device);
Kateryna Kostiukc867eb92020-03-08 13:15:17 -04001006 devicesVector.append(settings.name);
Kateryna Kostiuk64533102019-10-29 15:34:29 -04001007 } catch (...) {}
1008 }
1009 return devicesVector;
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -04001010}
1011
Kateryna Kostiuk32cf6be2019-10-28 12:22:45 -04001012-(NSString*) getDefaultDeviceName {
1013 auto type = mediaModel->getCurrentRenderedDevice(callUid_).type;
1014 switch (type) {
1015 case lrc::api::video::DeviceType::CAMERA:
Kateryna Kostiuk64533102019-10-29 15:34:29 -04001016 try {
1017 auto device = mediaModel->getCurrentRenderedDevice(callUid_).name;
1018 auto settings = mediaModel->getDeviceSettings(device);
Kateryna Kostiukc867eb92020-03-08 13:15:17 -04001019 return settings.name.toNSString();
Kateryna Kostiuk64533102019-10-29 15:34:29 -04001020 } catch (...) {}
Kateryna Kostiuk32cf6be2019-10-28 12:22:45 -04001021 case lrc::api::video::DeviceType::DISPLAY:
1022 return NSLocalizedString(@"Share screen", @"Contextual menu entry");
1023 default:
1024 return @"";
1025 }
1026}
1027
Kateryna Kostiukc867eb92020-03-08 13:15:17 -04001028-(void) switchToFile:(QString)uri {
1029 mediaModel->setInputFile(uri);
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -04001030}
1031
Kateryna Kostiuk6891d4f2019-09-19 17:44:33 -04001032-(CGRect) getVideoPreviewCollapsedSize {
1033 CGPoint origin;
1034 switch (movableBaseForView.closestCorner) {
1035 case TOP_LEFT:
Kateryna Kostiuk2aa39232019-10-10 11:55:11 -04001036 origin = CGPointMake(0, movableBaseForView.frame.size.height - HIDE_PREVIEW_BUTTON_SIZE);
Kateryna Kostiuk6891d4f2019-09-19 17:44:33 -04001037 break;
1038 case BOTTOM_LEFT:
1039 origin = CGPointMake(0, 0);
1040 break;
1041 case TOP_RIGHT:
Kateryna Kostiuk2aa39232019-10-10 11:55:11 -04001042 origin = CGPointMake(movableBaseForView.frame.size.width - HIDE_PREVIEW_BUTTON_SIZE, movableBaseForView.frame.size.height - HIDE_PREVIEW_BUTTON_SIZE);
Kateryna Kostiuk6891d4f2019-09-19 17:44:33 -04001043 break;
1044 case BOTTOM_RIGHT:
Kateryna Kostiuk2aa39232019-10-10 11:55:11 -04001045 origin = CGPointMake(movableBaseForView.frame.size.width - HIDE_PREVIEW_BUTTON_SIZE, 0);
Kateryna Kostiuk6891d4f2019-09-19 17:44:33 -04001046 break;
1047 }
Kateryna Kostiuk2aa39232019-10-10 11:55:11 -04001048 return CGRectMake(origin.x, origin.y, HIDE_PREVIEW_BUTTON_SIZE, HIDE_PREVIEW_BUTTON_SIZE);
Kateryna Kostiuk6891d4f2019-09-19 17:44:33 -04001049}
1050
Kateryna Kostiuk2aa39232019-10-10 11:55:11 -04001051-(CGRect) frameForExpendPreviewButton {
1052 CGPoint origin = CGPointMake(self.previewView.frame.size.width - HIDE_PREVIEW_BUTTON_SIZE,
1053 self.previewView.frame.size.height - HIDE_PREVIEW_BUTTON_SIZE);
1054 return CGRectMake(origin.x, origin.y, HIDE_PREVIEW_BUTTON_SIZE, HIDE_PREVIEW_BUTTON_SIZE);
Kateryna Kostiuk6891d4f2019-09-19 17:44:33 -04001055}
1056
Kateryna Kostiuk4db61092019-10-17 16:57:40 -04001057# pragma mark -ChooseContactVCDelegate
1058
Kateryna Kostiukc867eb92020-03-08 13:15:17 -04001059-(void)callToContact:(const QString&)contactUri convUID:(const QString&)convID {
Kateryna Kostiuk4db61092019-10-17 16:57:40 -04001060 if (brokerPopoverVC != nullptr) {
1061 [brokerPopoverVC performClose:self];
1062 brokerPopoverVC = NULL;
1063 }
1064 auto* callModel = accountInfo_->callModel.get();
1065 auto currentCall = callModel->getCall([self getcallID]);
1066 auto* convModel = accountInfo_->conversationModel.get();
1067 auto newCall = callModel->callAndAddParticipant(contactUri,
1068 [self getcallID],
1069 currentCall.isAudioOnly);
1070 [self addPreviewForContactUri:contactUri call: newCall];
1071}
1072
Kateryna Kostiukc867eb92020-03-08 13:15:17 -04001073-(void)joinCall:(const QString&)callId {
Kateryna Kostiuk4db61092019-10-17 16:57:40 -04001074 if (brokerPopoverVC != nullptr) {
1075 [brokerPopoverVC performClose:self];
1076 brokerPopoverVC = NULL;
1077 }
1078 auto* callModel = accountInfo_->callModel.get();
1079 callModel->joinCalls([self getcallID], callId);
1080}
1081
1082# pragma mark -CallInConferenceVCDelegate
1083
Kateryna Kostiukc867eb92020-03-08 13:15:17 -04001084-(void)removePreviewForContactUri:(const QString&)uri forCall:(const QString&) callId {
1085 NSMutableDictionary * calls = connectingCalls[callId.toNSString()];
Kateryna Kostiuk4db61092019-10-17 16:57:40 -04001086 if (!calls) {
1087 return;
1088 }
Kateryna Kostiukc867eb92020-03-08 13:15:17 -04001089 NSViewController *callView = calls[uri.toNSString()];
Kateryna Kostiuk4db61092019-10-17 16:57:40 -04001090 if (!callView) {
1091 return;
1092 }
Kateryna Kostiukc867eb92020-03-08 13:15:17 -04001093 calls[uri.toNSString()] = nil;
Kateryna Kostiuk4db61092019-10-17 16:57:40 -04001094 [self.callingWidgetsContainer removeView:callView.view];
1095}
1096
Kateryna Kostiukc867eb92020-03-08 13:15:17 -04001097-(void)addPreviewForContactUri:(const QString&)uri call:(const QString&)callId {
1098 NSMutableDictionary *calls = connectingCalls[callUid_.toNSString()];
Kateryna Kostiuk4db61092019-10-17 16:57:40 -04001099 if (!calls) {
1100 calls = [[NSMutableDictionary alloc] init];
1101 }
Kateryna Kostiukc867eb92020-03-08 13:15:17 -04001102 if (calls[uri.toNSString()]) {
Kateryna Kostiuk4db61092019-10-17 16:57:40 -04001103 return;
1104 }
1105 CallInConferenceVC *callingView = [self callingViewForCallId: callId];
Kateryna Kostiukc867eb92020-03-08 13:15:17 -04001106 calls[uri.toNSString()] = callingView;
1107 connectingCalls[callUid_.toNSString()] = calls;
Kateryna Kostiuk4db61092019-10-17 16:57:40 -04001108 [self.callingWidgetsContainer addView:callingView.view inGravity:NSStackViewGravityBottom];
1109 [self.callingWidgetsContainer updateConstraints];
1110 [self.callingWidgetsContainer updateLayer];
1111 [self.callingWidgetsContainer setNeedsDisplay:YES];
1112}
1113
Kateryna Kostiukc867eb92020-03-08 13:15:17 -04001114-(CallInConferenceVC*) callingViewForCallId:(const QString&)callId {
Kateryna Kostiuk4db61092019-10-17 16:57:40 -04001115 CallInConferenceVC *callView = [[CallInConferenceVC alloc]
1116 initWithNibName:@"CallInConferenceVC"
1117 bundle:nil
1118 callId:callId
1119 accountInfo:accountInfo_];
1120 callView.delegate = self;
1121 callView.initiatorCallId = callUid_;
1122 return callView;
1123}
1124
Kateryna Kostiukc867eb92020-03-08 13:15:17 -04001125-(const QString&)getcallID {
1126 return confUid_.isEmpty() ? callUid_ : confUid_;
Kateryna Kostiuk4db61092019-10-17 16:57:40 -04001127}
1128
Kateryna Kostiukc867eb92020-03-08 13:15:17 -04001129-(bool)isCurrentCall:(const QString&)callId {
Kateryna Kostiuk4db61092019-10-17 16:57:40 -04001130 return (callId == confUid_ || callId == callUid_);
1131}
1132
1133#pragma mark Popover delegate
1134
1135- (void)popoverWillClose:(NSNotification *)notification
1136{
1137 if (brokerPopoverVC != nullptr) {
1138 [brokerPopoverVC performClose:self];
1139 brokerPopoverVC = NULL;
1140 }
1141}
Alexandre Lisionc5148052015-03-04 15:10:35 -05001142@end