blob: 3164e69a68069c3f25943d61b377944c6223f6b9 [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"
20
21#import <QuartzCore/QuartzCore.h>
22
Alexandre Lision210fe212016-01-27 11:15:13 -050023///Qt
24#import <QMimeData>
25#import <QtMacExtras/qmacfunctions.h>
26#import <QtCore/qabstractitemmodel.h>
27#import <QItemSelectionModel>
28#import <QItemSelection>
29#import <QPixmap>
30
31///LRC
Alexandre Lisionc5148052015-03-04 15:10:35 -050032#import <video/previewmanager.h>
33#import <video/renderer.h>
Olivier Soldano994971f2017-12-05 16:30:12 -050034#import <api/newcallmodel.h>
35#import <api/call.h>
36#import <api/conversationmodel.h>
Alexandre Lision210fe212016-01-27 11:15:13 -050037#import <globalinstances.h>
Alexandre Lisionc5148052015-03-04 15:10:35 -050038
Alexandre Lision62005312016-01-28 15:55:16 -050039#import "AppDelegate.h"
Alexandre Lisionf47a2562015-06-15 15:48:29 -040040#import "views/ITProgressIndicator.h"
Alexandre Lision74dd47f2015-04-14 13:47:42 -040041#import "views/CallView.h"
Alexandre Lision210fe212016-01-27 11:15:13 -050042#import "delegates/ImageManipulationDelegate.h"
Alexandre Lision2db8f472015-07-22 15:05:46 -040043#import "PersonLinkerVC.h"
Alexandre Lision16d9c0a2015-08-10 12:05:15 -040044#import "ChatVC.h"
Alexandre Lision883719f2015-10-22 17:37:45 -040045#import "BrokerVC.h"
Alexandre Lision4baba4c2016-02-11 13:00:57 -050046#import "views/IconButton.h"
Anthony Léonard14e7bf32017-06-08 08:13:16 -040047#import "views/CallLayer.h"
Anthony Léonard6f819752018-01-05 09:53:40 -050048#import "utils.h"
Alexandre Lision74dd47f2015-04-14 13:47:42 -040049
Alexandre Lisionc5148052015-03-04 15:10:35 -050050@interface RendererConnectionsHolder : NSObject
51
52@property QMetaObject::Connection frameUpdated;
53@property QMetaObject::Connection started;
54@property QMetaObject::Connection stopped;
55
56@end
57
58@implementation RendererConnectionsHolder
59
60@end
61
Olivier Soldano994971f2017-12-05 16:30:12 -050062@interface CurrentCallVC () <NSPopoverDelegate, ContactLinkedDelegate> {
63 std::string convUid_;
64 std::string callUid_;
65 const lrc::api::account::Info *accountInfo_;
Anthony Léonard66a050c2018-01-03 16:32:34 -050066 NSTimer* refreshDurationTimer;
Olivier Soldano994971f2017-12-05 16:30:12 -050067}
Alexandre Lisionc5148052015-03-04 15:10:35 -050068
Alexandre Lision210fe212016-01-27 11:15:13 -050069// Main container
70@property (unsafe_unretained) IBOutlet NSSplitView* splitView;
71
Alexandre Lision89edc6a2015-11-09 11:30:47 -050072// Header info
73@property (unsafe_unretained) IBOutlet NSView* headerContainer;
Alexandre Lision883719f2015-10-22 17:37:45 -040074@property (unsafe_unretained) IBOutlet NSTextField* personLabel;
75@property (unsafe_unretained) IBOutlet NSTextField* stateLabel;
Alexandre Lision89edc6a2015-11-09 11:30:47 -050076@property (unsafe_unretained) IBOutlet NSTextField* timeSpentLabel;
Alexandre Lision210fe212016-01-27 11:15:13 -050077@property (unsafe_unretained) IBOutlet NSImageView* personPhoto;
Alexandre Lision89edc6a2015-11-09 11:30:47 -050078
Andreas Traczyk77a50d52018-05-08 17:47:31 -040079@property (unsafe_unretained) IBOutlet NSImageView* outgoingPhoto;
80@property (unsafe_unretained) IBOutlet NSTextField* outgoingPersonLabel;
81@property (unsafe_unretained) IBOutlet NSTextField* outgoingStateLabel;
82@property (unsafe_unretained) IBOutlet NSTextField* outgoingId;
83
Alexandre Lision89edc6a2015-11-09 11:30:47 -050084// Call Controls
85@property (unsafe_unretained) IBOutlet NSView* controlsPanel;
Alexandre Lision62005312016-01-28 15:55:16 -050086
Alexandre Lision4baba4c2016-02-11 13:00:57 -050087@property (unsafe_unretained) IBOutlet IconButton* holdOnOffButton;
88@property (unsafe_unretained) IBOutlet IconButton* hangUpButton;
89@property (unsafe_unretained) IBOutlet IconButton* recordOnOffButton;
90@property (unsafe_unretained) IBOutlet IconButton* pickUpButton;
91@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 Lision62005312016-01-28 15:55:16 -050098@property (unsafe_unretained) IBOutlet NSView* advancedPanel;
99@property (unsafe_unretained) IBOutlet IconButton* advancedButton;
100
Alexandre Lisiond18fa272015-06-15 11:18:03 -0400101
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500102// Join call panel
103@property (unsafe_unretained) IBOutlet NSView* joinPanel;
104@property (unsafe_unretained) IBOutlet NSButton* mergeCallsButton;
105
Alexandre Lision2db8f472015-07-22 15:05:46 -0400106@property (strong) NSPopover* addToContactPopover;
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500107@property (strong) NSPopover* brokerPopoverVC;
Alexandre Lision883719f2015-10-22 17:37:45 -0400108@property (strong) IBOutlet ChatVC* chatVC;
Alexandre Lisionf23ec5a2015-07-16 11:24:06 -0400109
Alexandre Lision210fe212016-01-27 11:15:13 -0500110// Ringing call panel
111@property (unsafe_unretained) IBOutlet NSView* ringingPanel;
112@property (unsafe_unretained) IBOutlet NSImageView* incomingPersonPhoto;
113@property (unsafe_unretained) IBOutlet NSTextField* incomingDisplayName;
114
115// Outgoing call panel
116@property (unsafe_unretained) IBOutlet NSView* outgoingPanel;
117@property (unsafe_unretained) IBOutlet ITProgressIndicator *loadingIndicator;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500118
119// Video
Alexandre Lision58cab672015-06-09 15:25:40 -0400120@property (unsafe_unretained) IBOutlet CallView *videoView;
Alexandre Lision58cab672015-06-09 15:25:40 -0400121@property (unsafe_unretained) IBOutlet NSView *previewView;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500122
123@property RendererConnectionsHolder* previewHolder;
124@property RendererConnectionsHolder* videoHolder;
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400125@property QMetaObject::Connection videoStarted;
Alexandre Lision4d9905e2016-01-22 12:01:36 -0500126@property QMetaObject::Connection selectedCallChanged;
Alexandre Lisionb65c0272015-07-22 15:51:29 -0400127@property QMetaObject::Connection messageConnection;
128@property QMetaObject::Connection mediaAddedConnection;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500129
130@end
131
132@implementation CurrentCallVC
Olivier Soldano994971f2017-12-05 16:30:12 -0500133@synthesize personLabel, personPhoto, stateLabel, holdOnOffButton, hangUpButton,
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500134 recordOnOffButton, pickUpButton, chatButton, transferButton, addParticipantButton, timeSpentLabel,
Olivier Soldano994971f2017-12-05 16:30:12 -0500135 muteVideoButton, muteAudioButton, controlsPanel, advancedPanel, advancedButton, headerContainer, videoView,
136 incomingDisplayName, incomingPersonPhoto, previewView, splitView, loadingIndicator, ringingPanel, joinPanel,
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400137 outgoingPanel, outgoingPersonLabel, outgoingStateLabel, outgoingPhoto, outgoingId;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500138
139@synthesize previewHolder;
140@synthesize videoHolder;
141
Olivier Soldano994971f2017-12-05 16:30:12 -0500142-(void) setCurrentCall:(const std::string&)callUid
143 conversation:(const std::string&)convUid
144 account:(const lrc::api::account::Info*)account;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500145{
Olivier Soldano994971f2017-12-05 16:30:12 -0500146 if(account == nil)
147 return;
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400148
Olivier Soldano994971f2017-12-05 16:30:12 -0500149 auto* callModel = account->callModel.get();
Alexandre Lisionc5148052015-03-04 15:10:35 -0500150
Olivier Soldano994971f2017-12-05 16:30:12 -0500151 if (not callModel->hasCall(callUid)){
152 callUid_.clear();
Alexandre Lision2db8f472015-07-22 15:05:46 -0400153 return;
154 }
Olivier Soldano994971f2017-12-05 16:30:12 -0500155 callUid_ = callUid;
156 convUid_ = convUid;
157 accountInfo_ = account;
Anthony Léonard4b0935f2017-12-26 12:05:22 -0500158 [self.chatVC setConversationUid:convUid model:account->conversationModel.get()];
Kateryna Kostiuk54d76972018-06-07 15:45:07 -0400159 auto currentCall = callModel->getCall(callUid_);
160 if(currentCall.isAudioOnly) {
161 muteVideoButton.image = [NSImage imageNamed:@"ic_action_mute_video.png"];
162 }
Alexandre Lisionc5148052015-03-04 15:10:35 -0500163}
164
165- (void)awakeFromNib
166{
167 NSLog(@"INIT CurrentCall VC");
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400168 [self.view setWantsLayer:YES];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500169
Alexandre Lisionc5148052015-03-04 15:10:35 -0500170 [previewView setWantsLayer:YES];
Alexandre Lision22d615b2016-01-25 12:54:34 -0500171 [previewView.layer setBackgroundColor:[NSColor blackColor].CGColor];
172 [previewView.layer setContentsGravity:kCAGravityResizeAspectFill];
173 [previewView.layer setFrame:previewView.frame];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500174
175 [controlsPanel setWantsLayer:YES];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500176 [controlsPanel.layer setBackgroundColor:[NSColor clearColor].CGColor];
177 [controlsPanel.layer setFrame:controlsPanel.frame];
178
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400179 previewHolder = [[RendererConnectionsHolder alloc] init];
180 videoHolder = [[RendererConnectionsHolder alloc] init];
181
Alexandre Lisionf47a2562015-06-15 15:48:29 -0400182 [loadingIndicator setColor:[NSColor whiteColor]];
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400183 [loadingIndicator setNumberOfLines:200];
184 [loadingIndicator setWidthOfLine:4];
185 [loadingIndicator setLengthOfLine:4];
186 [loadingIndicator setInnerMargin:59];
Alexandre Lisionf47a2562015-06-15 15:48:29 -0400187
Alexandre Lisiona1eee3c2015-08-10 13:44:51 -0400188 [self.videoView setCallDelegate:self];
Kateryna Kostiuk1004caa2018-03-29 13:48:07 -0400189 CGColor* color = [[[NSColor blackColor] colorWithAlphaComponent:0.2] CGColor];
190 [headerContainer.layer setBackgroundColor:color];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500191}
192
Anthony Léonard66a050c2018-01-03 16:32:34 -0500193-(void) updateDurationLabel
194{
195 if (accountInfo_ != nil) {
196 auto* callModel = accountInfo_->callModel.get();
197 if (callModel->hasCall(callUid_)) {
198 auto& callStatus = callModel->getCall(callUid_).status;
199 if (callStatus != lrc::api::call::Status::ENDED &&
200 callStatus != lrc::api::call::Status::TERMINATING &&
201 callStatus != lrc::api::call::Status::INVALID) {
202 [timeSpentLabel setStringValue:@(callModel->getFormattedCallDuration(callUid_).c_str())];
203 return;
204 }
205 }
206 }
207
208 // If call is not running anymore or accountInfo_ is not set for any reason
209 // we stop the refresh loop
210 [refreshDurationTimer invalidate];
211 refreshDurationTimer = nil;
212 [timeSpentLabel setHidden:YES];
213}
214
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400215-(void) updateCall
Alexandre Lisionc5148052015-03-04 15:10:35 -0500216{
Olivier Soldano994971f2017-12-05 16:30:12 -0500217 if (accountInfo_ == nil)
218 return;
Alexandre Lisionbb5dbcd2015-07-09 16:36:47 -0400219
Olivier Soldano994971f2017-12-05 16:30:12 -0500220 auto* callModel = accountInfo_->callModel.get();
221 if (not callModel->hasCall(callUid_)) {
222 return;
223 }
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500224
Olivier Soldano994971f2017-12-05 16:30:12 -0500225 auto currentCall = callModel->getCall(callUid_);
226 NSLog(@"\n status %@ \n",@(lrc::api::call::to_string(currentCall.status).c_str()));
Anthony Léonard8ee26782018-01-05 10:23:04 -0500227 auto convIt = getConversationFromUid(convUid_, *accountInfo_->conversationModel);
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400228 if (convIt != accountInfo_->conversationModel->allFilteredConversations().end()) {
229 NSString* bestName = bestNameForConversation(*convIt, *accountInfo_->conversationModel);
230 [personLabel setStringValue:bestName];
231 [outgoingPersonLabel setStringValue:bestName];
232 NSString* ringID = bestIDForConversation(*convIt, *accountInfo_->conversationModel);
233 if([bestName isEqualToString:ringID]) {
234 ringID = @"";
235 }
236 [outgoingId setStringValue:ringID];
237 }
238
Anthony Léonard66a050c2018-01-03 16:32:34 -0500239 [timeSpentLabel setStringValue:@(callModel->getFormattedCallDuration(callUid_).c_str())];
Anthony Léonard66a050c2018-01-03 16:32:34 -0500240 if (refreshDurationTimer == nil)
241 refreshDurationTimer = [NSTimer scheduledTimerWithTimeInterval:1.0
242 target:self
243 selector:@selector(updateDurationLabel)
244 userInfo:nil
245 repeats:YES];
Olivier Soldano994971f2017-12-05 16:30:12 -0500246 [stateLabel setStringValue:@(to_string(currentCall.status).c_str())];
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400247 [outgoingStateLabel setStringValue:@(to_string(currentCall.status).c_str())];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500248
Olivier Soldano994971f2017-12-05 16:30:12 -0500249 // Default values for this views
250 [loadingIndicator setHidden:YES];
Olivier Soldano994971f2017-12-05 16:30:12 -0500251 [ringingPanel setHidden:YES];
252 [outgoingPanel setHidden:YES];
253 [controlsPanel setHidden:NO];
254 [headerContainer setHidden:NO];
Anthony Léonard4b0935f2017-12-26 12:05:22 -0500255 [chatButton setHidden:NO];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500256
Olivier Soldano994971f2017-12-05 16:30:12 -0500257 using Status = lrc::api::call::Status;
258 switch (currentCall.status) {
259 case Status::SEARCHING:
260 case Status::OUTGOING_REQUESTED:
261 case Status::CONNECTING:
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400262 [headerContainer setHidden:YES];
263 [outgoingPanel setHidden:NO];
264 [outgoingPhoto setHidden:NO];
265 [self setupContactInfo:outgoingPhoto];
Olivier Soldano994971f2017-12-05 16:30:12 -0500266 [loadingIndicator setHidden:NO];
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400267 [controlsPanel setHidden:YES];
Olivier Soldano994971f2017-12-05 16:30:12 -0500268 break;
269 case Status::INCOMING_RINGING:
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400270 [outgoingPhoto setHidden:YES];
Olivier Soldano994971f2017-12-05 16:30:12 -0500271 [controlsPanel setHidden:YES];
272 [outgoingPanel setHidden:YES];
273 [self setupIncoming:callUid_];
274 break;
275 case Status::OUTGOING_RINGING:
276 [controlsPanel setHidden:YES];
277 [outgoingPanel setHidden:NO];
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400278 [loadingIndicator setHidden:NO];
279 [headerContainer setHidden:YES];
Olivier Soldano994971f2017-12-05 16:30:12 -0500280 break;
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400281 /*case Status::CONFERENCE:
282 [self setupConference:currentCall];
283 break;*/
Olivier Soldano994971f2017-12-05 16:30:12 -0500284 case Status::PAUSED:
285 case Status::PEER_PAUSED:
286 case Status::INACTIVE:
287 case Status::IN_PROGRESS:
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400288 // change constraints (uncollapse avatar)
289 [self setupContactInfo:personPhoto];
Kateryna Kostiuk1004caa2018-03-29 13:48:07 -0400290 [timeSpentLabel setHidden:NO];
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400291 [outgoingPhoto setHidden:YES];
292 [headerContainer setHidden:NO];
293 break;
Olivier Soldano994971f2017-12-05 16:30:12 -0500294 case Status::CONNECTED:
295 case Status::AUTO_ANSWERING:
296 break;
297 case Status::ENDED:
298 case Status::TERMINATING:
299 case Status::INVALID:
300 [controlsPanel setHidden:YES];
301 [outgoingPanel setHidden:NO];
Andreas Traczykecdc4fa2018-03-22 16:11:47 -0400302 [self hideWithAnimation:false];
Olivier Soldano994971f2017-12-05 16:30:12 -0500303 break;
304 }
Alexandre Lision4d9905e2016-01-22 12:01:36 -0500305
Alexandre Lision4d9905e2016-01-22 12:01:36 -0500306}
307
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400308-(void) setupContactInfo:(NSImageView*)imageView
309{
310 auto* convModel = accountInfo_->conversationModel.get();
311 auto it = getConversationFromUid(convUid_, *convModel);
312 if (it != convModel->allFilteredConversations().end()) {
313 auto& imgManip = reinterpret_cast<Interfaces::ImageManipulationDelegate&>(GlobalInstances::pixmapManipulator());
314 QVariant photo = imgManip.conversationPhoto(*it, *accountInfo_, QSize(120, 120), NO);
315 [imageView setImage:QtMac::toNSImage(qvariant_cast<QPixmap>(photo))];
316 }
317}
318
Olivier Soldano994971f2017-12-05 16:30:12 -0500319-(void) setupIncoming:(const std::string&) callId
Alexandre Lision4d9905e2016-01-22 12:01:36 -0500320{
Olivier Soldano994971f2017-12-05 16:30:12 -0500321 if (accountInfo_ == nil)
322 return;
323
324 auto* callModel = accountInfo_->callModel.get();
325 if (not callModel->hasCall(callUid_)) {
326 return;
327 }
328
329 auto call = callModel->getCall(callUid_);
330 auto* convModel = accountInfo_->conversationModel.get();
331
332 [ringingPanel setHidden:NO];
333 [controlsPanel setHidden:YES];
334 [headerContainer setHidden:YES];
Anthony Léonard6f819752018-01-05 09:53:40 -0500335 auto it = getConversationFromUid(convUid_, *convModel);
Olivier Soldano994971f2017-12-05 16:30:12 -0500336 if (it != convModel->allFilteredConversations().end()) {
337 auto& imgManip = reinterpret_cast<Interfaces::ImageManipulationDelegate&>(GlobalInstances::pixmapManipulator());
338 QVariant photo = imgManip.conversationPhoto(*it, *accountInfo_);
339 [incomingPersonPhoto setImage:QtMac::toNSImage(qvariant_cast<QPixmap>(photo))];
Anthony Léonard8ee26782018-01-05 10:23:04 -0500340 [incomingDisplayName setStringValue:bestNameForConversation(*it, *convModel)];
Olivier Soldano994971f2017-12-05 16:30:12 -0500341 }
342}
343
344
345-(void) setupConference:(Call*) c
346{
347 [videoView setShouldAcceptInteractions:YES];
348 [self.chatButton setHidden:NO];
349 [joinPanel setHidden:YES];
350 [self.addParticipantButton setHidden:NO];
351 [self.transferButton setHidden:YES];
352}
353
354-(void)collapseRightView
355{
356 NSView *right = [[splitView subviews] objectAtIndex:1];
357 NSView *left = [[splitView subviews] objectAtIndex:0];
358 NSRect leftFrame = [left frame];
359 [right setHidden:YES];
360 [splitView display];
361}
362
363- (void) changeCallSelection:(std::string&)callUid
364{
365 if (accountInfo_ == nil)
366 return;
367
368 auto* callModel = accountInfo_->callModel.get();
369 if (not callModel->hasCall(callUid)) {
370 return;
371 }
372
Alexandre Lision4d9905e2016-01-22 12:01:36 -0500373 QObject::disconnect(self.selectedCallChanged);
Olivier Soldano994971f2017-12-05 16:30:12 -0500374 self.selectedCallChanged = QObject::connect(callModel,
375 &lrc::api::NewCallModel::callStatusChanged,
376 [self](const std::string callId) {
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400377 [self updateCall];
Alexandre Lision4d9905e2016-01-22 12:01:36 -0500378 });
Alexandre Lisionc5148052015-03-04 15:10:35 -0500379}
380
381-(void) connectVideoSignals
382{
Olivier Soldano994971f2017-12-05 16:30:12 -0500383 if (accountInfo_ == nil)
384 return;
385
386 auto* callModel = accountInfo_->callModel.get();
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500387 QObject::disconnect(self.videoStarted);
Olivier Soldano994971f2017-12-05 16:30:12 -0500388 self.videoStarted = QObject::connect(callModel,
389 &lrc::api::NewCallModel::remotePreviewStarted,
390 [self](const std::string& callId, Video::Renderer* renderer) {
391 NSLog(@"Video started!");
Kateryna Kostiuk1004caa2018-03-29 13:48:07 -0400392 [videoView setShouldAcceptInteractions:YES];
393 [self mouseIsMoving: NO];
Olivier Soldano994971f2017-12-05 16:30:12 -0500394 [self connectVideoRenderer:renderer];
395 });
Alexandre Lisionc5148052015-03-04 15:10:35 -0500396
Olivier Soldano994971f2017-12-05 16:30:12 -0500397 if (callModel->hasCall(callUid_)) {
398 if (auto renderer = callModel->getRenderer(callUid_)) {
399 QObject::disconnect(self.videoStarted);
400 [self connectVideoRenderer: renderer];
401 }
Alexandre Lisionc5148052015-03-04 15:10:35 -0500402 }
Alexandre Lisionc5148052015-03-04 15:10:35 -0500403 [self connectPreviewRenderer];
404
405}
406
407-(void) connectPreviewRenderer
408{
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400409 QObject::disconnect(previewHolder.frameUpdated);
410 QObject::disconnect(previewHolder.stopped);
411 QObject::disconnect(previewHolder.started);
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400412 previewHolder.started = QObject::connect(&Video::PreviewManager::instance(),
Alexandre Lisionc5148052015-03-04 15:10:35 -0500413 &Video::PreviewManager::previewStarted,
414 [=](Video::Renderer* renderer) {
Alexandre Lisionc5148052015-03-04 15:10:35 -0500415 QObject::disconnect(previewHolder.frameUpdated);
416 previewHolder.frameUpdated = QObject::connect(renderer,
417 &Video::Renderer::frameUpdated,
418 [=]() {
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400419 [self renderer:Video::PreviewManager::instance().previewRenderer()
Anthony Léonard14e7bf32017-06-08 08:13:16 -0400420 renderFrameForPreviewView:previewView];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500421 });
422 });
423
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400424 previewHolder.stopped = QObject::connect(&Video::PreviewManager::instance(),
Alexandre Lisionc5148052015-03-04 15:10:35 -0500425 &Video::PreviewManager::previewStopped,
426 [=](Video::Renderer* renderer) {
Alexandre Lisionc5148052015-03-04 15:10:35 -0500427 QObject::disconnect(previewHolder.frameUpdated);
428 [previewView.layer setContents:nil];
429 });
430
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400431 previewHolder.frameUpdated = QObject::connect(Video::PreviewManager::instance().previewRenderer(),
Alexandre Lisionc5148052015-03-04 15:10:35 -0500432 &Video::Renderer::frameUpdated,
433 [=]() {
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400434 [self renderer:Video::PreviewManager::instance().previewRenderer()
Anthony Léonard14e7bf32017-06-08 08:13:16 -0400435 renderFrameForPreviewView:previewView];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500436 });
437}
438
439-(void) connectVideoRenderer: (Video::Renderer*)renderer
440{
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400441 QObject::disconnect(videoHolder.frameUpdated);
442 QObject::disconnect(videoHolder.started);
443 QObject::disconnect(videoHolder.stopped);
Olivier Soldano994971f2017-12-05 16:30:12 -0500444
445 if(renderer == nil)
446 return;
447
Alexandre Lisionc5148052015-03-04 15:10:35 -0500448 videoHolder.frameUpdated = QObject::connect(renderer,
449 &Video::Renderer::frameUpdated,
450 [=]() {
Anthony Léonard14e7bf32017-06-08 08:13:16 -0400451 [self renderer:renderer renderFrameForDistantView:videoView];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500452 });
453
454 videoHolder.started = QObject::connect(renderer,
455 &Video::Renderer::started,
456 [=]() {
Kateryna Kostiuk1004caa2018-03-29 13:48:07 -0400457 [self mouseIsMoving: NO];
458 [videoView setShouldAcceptInteractions:YES];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500459 QObject::disconnect(videoHolder.frameUpdated);
460 videoHolder.frameUpdated = QObject::connect(renderer,
461 &Video::Renderer::frameUpdated,
462 [=]() {
Anthony Léonard14e7bf32017-06-08 08:13:16 -0400463 [self renderer:renderer renderFrameForDistantView:videoView];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500464 });
465 });
466
467 videoHolder.stopped = QObject::connect(renderer,
468 &Video::Renderer::stopped,
469 [=]() {
Kateryna Kostiuk1004caa2018-03-29 13:48:07 -0400470 [self mouseIsMoving: YES];
471 [videoView setShouldAcceptInteractions:NO];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500472 QObject::disconnect(videoHolder.frameUpdated);
Anthony Léonard14e7bf32017-06-08 08:13:16 -0400473 [(CallLayer*)videoView.layer setVideoRunning:NO];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500474 });
475}
476
Anthony Léonard14e7bf32017-06-08 08:13:16 -0400477-(void) renderer: (Video::Renderer*)renderer renderFrameForPreviewView:(NSView*) view
Alexandre Lisionc5148052015-03-04 15:10:35 -0500478{
Alexandre Lisionc5148052015-03-04 15:10:35 -0500479 QSize res = renderer->size();
480
Alexandre Lision6731e132015-10-14 14:29:06 -0400481 auto frame_ptr = renderer->currentFrame();
482 auto frame_data = frame_ptr.ptr;
483 if (!frame_data)
484 return;
485
Alexandre Lisionc5148052015-03-04 15:10:35 -0500486 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
Alexandre Lision6731e132015-10-14 14:29:06 -0400487 CGContextRef newContext = CGBitmapContextCreate(frame_data,
Alexandre Lisionc5148052015-03-04 15:10:35 -0500488 res.width(),
489 res.height(),
490 8,
491 4*res.width(),
492 colorSpace,
493 kCGImageAlphaPremultipliedLast);
494
495
496 CGImageRef newImage = CGBitmapContextCreateImage(newContext);
497
498 /*We release some components*/
499 CGContextRelease(newContext);
500 CGColorSpaceRelease(colorSpace);
501
502 [CATransaction begin];
503 view.layer.contents = (__bridge id)newImage;
504 [CATransaction commit];
505
506 CFRelease(newImage);
507}
508
Anthony Léonard14e7bf32017-06-08 08:13:16 -0400509-(void) renderer: (Video::Renderer*)renderer renderFrameForDistantView:(CallView*) view
510{
Anthony Léonard14e7bf32017-06-08 08:13:16 -0400511 auto frame_ptr = renderer->currentFrame();
512 if (!frame_ptr.ptr)
513 return;
514
515 CallLayer* callLayer = (CallLayer*) view.layer;
516
Anthony Léonarda9d7c8e2018-01-03 14:41:17 -0500517 [callLayer setCurrentFrame:std::move(frame_ptr)];
Anthony Léonard14e7bf32017-06-08 08:13:16 -0400518 [callLayer setVideoRunning:YES];
519}
520
Alexandre Lisionc5148052015-03-04 15:10:35 -0500521- (void) initFrame
522{
523 [self.view setFrame:self.view.superview.bounds];
524 [self.view setHidden:YES];
525 self.view.layer.position = self.view.frame.origin;
Alexandre Lisionbb5dbcd2015-07-09 16:36:47 -0400526 [self collapseRightView];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500527}
528
529# pragma private IN/OUT animations
530
Olivier Soldano994971f2017-12-05 16:30:12 -0500531-(void)uncollapseRightView
532{
533 NSView *left = [[splitView subviews] objectAtIndex:0];
534 NSView *right = [[splitView subviews] objectAtIndex:1];
535 [right setHidden:NO];
536
537 CGFloat dividerThickness = [splitView dividerThickness];
538
539 // get the different frames
540 NSRect leftFrame = [left frame];
541 NSRect rightFrame = [right frame];
542
543 leftFrame.size.width = (leftFrame.size.width - rightFrame.size.width - dividerThickness);
544 rightFrame.origin.x = leftFrame.size.width + dividerThickness;
545 [left setFrameSize:leftFrame.size];
546 [right setFrame:rightFrame];
547 [splitView display];
548
549 [self.chatVC takeFocus];
550}
551
Alexandre Lisionc5148052015-03-04 15:10:35 -0500552-(void) cleanUp
553{
Anthony Léonard5c287642018-02-21 15:54:19 -0500554 if(self.splitView.isInFullScreenMode)
555 [self.splitView exitFullScreenModeWithOptions:nil];
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400556 QObject::disconnect(videoHolder.frameUpdated);
557 QObject::disconnect(videoHolder.started);
558 QObject::disconnect(videoHolder.stopped);
559 QObject::disconnect(previewHolder.frameUpdated);
560 QObject::disconnect(previewHolder.stopped);
561 QObject::disconnect(previewHolder.started);
Anthony Léonardc0013bb2018-02-20 16:23:02 -0500562 QObject::disconnect(self.messageConnection);
Alexandre Lisionc5148052015-03-04 15:10:35 -0500563 [previewView.layer setContents:nil];
Kateryna Kostiuk1004caa2018-03-29 13:48:07 -0400564 [(CallLayer*)videoView.layer setVideoRunning:NO];
Alexandre Lision883719f2015-10-22 17:37:45 -0400565
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500566 [_brokerPopoverVC performClose:self];
Alexandre Lision883719f2015-10-22 17:37:45 -0400567 [self.addToContactPopover performClose:self];
Alexandre Lision0e66aea2015-11-02 16:36:30 -0500568
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500569 [self.chatButton setHidden:YES];
570 [self.addParticipantButton setHidden:YES];
571 [self.transferButton setHidden:YES];
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400572 [self.qualityButton setHidden:YES];
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500573
Alexandre Lision4baba4c2016-02-11 13:00:57 -0500574 [self.chatButton setPressed:NO];
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500575 [self.mergeCallsButton setState:NSOffState];
Alexandre Lision883719f2015-10-22 17:37:45 -0400576 [self collapseRightView];
Alexandre Lision57227772016-01-15 17:19:36 -0500577
578 [personLabel setStringValue:@""];
579 [timeSpentLabel setStringValue:@""];
580 [stateLabel setStringValue:@""];
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400581
582 [outgoingPersonLabel setStringValue:@""];
583 [outgoingStateLabel setStringValue:@""];
Alexandre Lision62005312016-01-28 15:55:16 -0500584
585 [advancedButton setPressed:NO];
586 [advancedPanel setHidden:YES];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500587}
588
Andreas Traczykecdc4fa2018-03-22 16:11:47 -0400589-(void) setupCallView
590{
591 if (accountInfo_ == nil)
592 return;
593
594 auto* callModel = accountInfo_->callModel.get();
595 auto* convModel = accountInfo_->conversationModel.get();
596
597 // when call comes in we want to show the controls/header
Kateryna Kostiuk1004caa2018-03-29 13:48:07 -0400598 [self mouseIsMoving: YES];
599 [videoView setShouldAcceptInteractions: NO];
Andreas Traczykecdc4fa2018-03-22 16:11:47 -0400600
601 [self connectVideoSignals];
602 /* check if text media is already present */
603 if(not callModel->hasCall(callUid_))
604 return;
605
606 [loadingIndicator setAnimates:YES];
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400607 [self updateCall];
Andreas Traczykecdc4fa2018-03-22 16:11:47 -0400608
609 /* monitor media for messaging text messaging */
610 QObject::disconnect(self.messageConnection);
611 self.messageConnection = QObject::connect(convModel,
612 &lrc::api::ConversationModel::interactionStatusUpdated,
613 [self] (std::string convUid,
614 uint64_t msgId,
615 lrc::api::interaction::Info msg) {
616 if (msg.type == lrc::api::interaction::Type::TEXT) {
617 if(not [[self splitView] isSubviewCollapsed:[[[self splitView] subviews] objectAtIndex: 1]]){
618 return;
619 }
620 [self uncollapseRightView];
621 }
622 });
623}
624
625-(void) showWithAnimation:(BOOL)animate
626{
627 if (!animate) {
628 [self.view setHidden:NO];
629 [self setupCallView];
630 return;
631 }
632
633 CGRect frame = CGRectOffset(self.view.superview.bounds, -self.view.superview.bounds.size.width, 0);
634 [self.view setHidden:NO];
635
636 [CATransaction begin];
637 CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
638 [animation setFromValue:[NSValue valueWithPoint:frame.origin]];
639 [animation setToValue:[NSValue valueWithPoint:self.view.superview.bounds.origin]];
640 [animation setDuration:0.2f];
641 [animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]];
642 [CATransaction setCompletionBlock:^{
643 [self setupCallView];
644 }];
645
646 [self.view.layer addAnimation:animation forKey:animation.keyPath];
647 [CATransaction commit];
648}
649
650-(void) hideWithAnimation:(BOOL)animate
Alexandre Lisionc5148052015-03-04 15:10:35 -0500651{
Alexandre Lisionc5148052015-03-04 15:10:35 -0500652 if(self.view.frame.origin.x < 0) {
Alexandre Lisionc5148052015-03-04 15:10:35 -0500653 return;
654 }
655
Andreas Traczykecdc4fa2018-03-22 16:11:47 -0400656 if (!animate) {
Kateryna Kostiuk1004caa2018-03-29 13:48:07 -0400657 [self cleanUp];
Andreas Traczykecdc4fa2018-03-22 16:11:47 -0400658 [self.view setHidden:YES];
659 return;
660 }
661
Alexandre Lisionc5148052015-03-04 15:10:35 -0500662 CGRect frame = CGRectOffset(self.view.frame, -self.view.frame.size.width, 0);
663 [CATransaction begin];
664 CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
665 [animation setFromValue:[NSValue valueWithPoint:self.view.frame.origin]];
666 [animation setToValue:[NSValue valueWithPoint:frame.origin]];
667 [animation setDuration:0.2f];
Alexandre Lision22d615b2016-01-25 12:54:34 -0500668 [animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500669
670 [CATransaction setCompletionBlock:^{
671 [self.view setHidden:YES];
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400672 // first make sure everything is disconnected
Alexandre Lisionc5148052015-03-04 15:10:35 -0500673 [self cleanUp];
Olivier Soldano994971f2017-12-05 16:30:12 -0500674// if (currentCall_) {
675// [self animateIn];
676// }
Alexandre Lisionc5148052015-03-04 15:10:35 -0500677 }];
678 [self.view.layer addAnimation:animation forKey:animation.keyPath];
Alexandre Lisiona1c6d752015-06-23 12:27:38 -0400679
680 [self.view.layer setPosition:frame.origin];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500681 [CATransaction commit];
682}
683
684/**
685 * Debug purpose
686 */
687-(void) dumpFrame:(CGRect) frame WithName:(NSString*) name
688{
689 NSLog(@"frame %@ : %f %f %f %f \n\n",name ,frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
690}
691
Alexandre Lision58cab672015-06-09 15:25:40 -0400692#pragma mark - Button methods
693
Alexandre Lisionc5148052015-03-04 15:10:35 -0500694- (IBAction)hangUp:(id)sender {
Olivier Soldano994971f2017-12-05 16:30:12 -0500695 if (accountInfo_ == nil)
696 return;
697
698 auto* callModel = accountInfo_->callModel.get();
699
700 callModel->hangUp(callUid_);
Alexandre Lisionc5148052015-03-04 15:10:35 -0500701}
702
703- (IBAction)accept:(id)sender {
Olivier Soldano994971f2017-12-05 16:30:12 -0500704 if (accountInfo_ == nil)
705 return;
706
Anthony Léonardf584cc52018-01-19 12:00:19 -0500707 // If we accept a conversation with a non trusted contact, we first accept it
708 auto convIt = getConversationFromUid(convUid_, *accountInfo_->conversationModel.get());
709 if (convIt != accountInfo_->conversationModel->allFilteredConversations().end()) {
710 auto& contact = accountInfo_->contactModel->getContact(convIt->participants[0]);
711 if (contact.profileInfo.type == lrc::api::profile::Type::PENDING)
712 accountInfo_->conversationModel->makePermanent(convUid_);
713 }
714
Olivier Soldano994971f2017-12-05 16:30:12 -0500715 auto* callModel = accountInfo_->callModel.get();
716
717 callModel->accept(callUid_);
Alexandre Lisionc5148052015-03-04 15:10:35 -0500718}
719
720- (IBAction)toggleRecording:(id)sender {
Olivier Soldano994971f2017-12-05 16:30:12 -0500721 if (accountInfo_ == nil)
722 return;
723
724 auto* callModel = accountInfo_->callModel.get();
725
726 callModel->toggleAudioRecord(callUid_);
Kateryna Kostiuk54d76972018-06-07 15:45:07 -0400727 [recordOnOffButton setPressed:!recordOnOffButton.isPressed];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500728}
729
730- (IBAction)toggleHold:(id)sender {
Olivier Soldano994971f2017-12-05 16:30:12 -0500731 if (accountInfo_ == nil)
732 return;
733
734 auto* callModel = accountInfo_->callModel.get();
Kateryna Kostiuk54d76972018-06-07 15:45:07 -0400735 auto currentCall = callModel->getCall(callUid_);
736 if (currentCall.status != lrc::api::call::Status::PAUSED) {
737 holdOnOffButton.image = [NSImage imageNamed:@"ic_action_holdoff.png"];
738 } else {
739 holdOnOffButton.image = [NSImage imageNamed:@"ic_action_hold.png"];
740 }
Olivier Soldano994971f2017-12-05 16:30:12 -0500741
742 callModel->togglePause(callUid_);
Alexandre Lisionc5148052015-03-04 15:10:35 -0500743}
744
Alexandre Lision62005312016-01-28 15:55:16 -0500745- (IBAction)toggleAdvancedControls:(id)sender {
746 [advancedButton setPressed:!advancedButton.isPressed];
747 [advancedPanel setHidden:![advancedButton isPressed]];
748}
749
750- (IBAction)showDialpad:(id)sender {
751 AppDelegate* appDelegate = (AppDelegate *)[[NSApplication sharedApplication] delegate];
752 [appDelegate showDialpad];
753}
754
Alexandre Lision58cab672015-06-09 15:25:40 -0400755-(IBAction)toggleChat:(id)sender;
756{
757 BOOL rightViewCollapsed = [[self splitView] isSubviewCollapsed:[[[self splitView] subviews] objectAtIndex: 1]];
758 if (rightViewCollapsed) {
759 [self uncollapseRightView];
Alexandre Lision58cab672015-06-09 15:25:40 -0400760 } else {
761 [self collapseRightView];
762 }
Alexandre Lision62005312016-01-28 15:55:16 -0500763 [chatButton setPressed:rightViewCollapsed];
Alexandre Lision58cab672015-06-09 15:25:40 -0400764}
765
Alexandre Lisiond18fa272015-06-15 11:18:03 -0400766- (IBAction)muteAudio:(id)sender
767{
Olivier Soldano994971f2017-12-05 16:30:12 -0500768 if (accountInfo_ == nil)
769 return;
770
771 auto* callModel = accountInfo_->callModel.get();
Kateryna Kostiuk54d76972018-06-07 15:45:07 -0400772 auto currentCall = callModel->getCall(callUid_);
773 if (currentCall.audioMuted) {
774 muteAudioButton.image = [NSImage imageNamed:@"ic_action_audio.png"];
775 } else {
776 muteAudioButton.image = [NSImage imageNamed:@"ic_action_mute_audio.png"];
777 }
Olivier Soldano994971f2017-12-05 16:30:12 -0500778 callModel->toggleMedia(callUid_, lrc::api::NewCallModel::Media::AUDIO);
Alexandre Lisiond18fa272015-06-15 11:18:03 -0400779}
780
781- (IBAction)muteVideo:(id)sender
782{
Olivier Soldano994971f2017-12-05 16:30:12 -0500783 if (accountInfo_ == nil)
784 return;
Olivier Soldano994971f2017-12-05 16:30:12 -0500785 auto* callModel = accountInfo_->callModel.get();
Kateryna Kostiuk54d76972018-06-07 15:45:07 -0400786 auto currentCall = callModel->getCall(callUid_);
787 if(!currentCall.isAudioOnly) {
788 if (currentCall.videoMuted) {
789 muteVideoButton.image = [NSImage imageNamed:@"ic_action_video.png"];
790 } else {
791 muteVideoButton.image = [NSImage imageNamed:@"ic_action_mute_video.png"];
792 }
793 }
Olivier Soldano994971f2017-12-05 16:30:12 -0500794 callModel->toggleMedia(callUid_, lrc::api::NewCallModel::Media::VIDEO);
Alexandre Lisiond18fa272015-06-15 11:18:03 -0400795}
Alexandre Lision883719f2015-10-22 17:37:45 -0400796
797- (IBAction)toggleTransferView:(id)sender {
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500798 if (_brokerPopoverVC != nullptr) {
799 [_brokerPopoverVC performClose:self];
800 _brokerPopoverVC = NULL;
Alexandre Lision62005312016-01-28 15:55:16 -0500801 [self.transferButton setPressed:NO];
Alexandre Lision883719f2015-10-22 17:37:45 -0400802 } else {
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500803 auto* brokerVC = [[BrokerVC alloc] initWithMode:BrokerMode::TRANSFER];
804 _brokerPopoverVC = [[NSPopover alloc] init];
805 [_brokerPopoverVC setContentSize:brokerVC.view.frame.size];
806 [_brokerPopoverVC setContentViewController:brokerVC];
807 [_brokerPopoverVC setAnimates:YES];
808 [_brokerPopoverVC setBehavior:NSPopoverBehaviorTransient];
809 [_brokerPopoverVC setDelegate:self];
810 [_brokerPopoverVC showRelativeToRect:[sender bounds] ofView:sender preferredEdge:NSMinYEdge];
Alexandre Lision883719f2015-10-22 17:37:45 -0400811 [videoView setCallDelegate:nil];
812 }
Alexandre Lisionf23ec5a2015-07-16 11:24:06 -0400813}
Alexandre Lisiond18fa272015-06-15 11:18:03 -0400814
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500815- (IBAction)toggleAddParticipantView:(id)sender {
816 if (_brokerPopoverVC != nullptr) {
817 [_brokerPopoverVC performClose:self];
818 _brokerPopoverVC = NULL;
Alexandre Lision62005312016-01-28 15:55:16 -0500819 [self.addParticipantButton setPressed:NO];
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500820 } else {
821 auto* brokerVC = [[BrokerVC alloc] initWithMode:BrokerMode::CONFERENCE];
822 _brokerPopoverVC = [[NSPopover alloc] init];
823 [_brokerPopoverVC setContentSize:brokerVC.view.frame.size];
824 [_brokerPopoverVC setContentViewController:brokerVC];
825 [_brokerPopoverVC setAnimates:YES];
826 [_brokerPopoverVC setBehavior:NSPopoverBehaviorTransient];
827 [_brokerPopoverVC setDelegate:self];
828 [_brokerPopoverVC showRelativeToRect:[sender bounds] ofView:sender preferredEdge:NSMinYEdge];
829 [videoView setCallDelegate:nil];
830 }
831}
832
833/**
834 * Merge current call with its parent call
835 */
836- (IBAction)mergeCalls:(id)sender
837{
Olivier Soldano994971f2017-12-05 16:30:12 -0500838// auto current = CallModel::instance().selectedCall();
839// current->joinToParent();
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500840}
841
Alexandre Lision2db8f472015-07-22 15:05:46 -0400842#pragma mark - NSPopOverDelegate
843
Alexandre Lision266fca02015-09-28 14:47:05 -0400844- (void)popoverWillClose:(NSNotification *)notification
845{
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500846 if (_brokerPopoverVC != nullptr) {
847 [_brokerPopoverVC performClose:self];
848 _brokerPopoverVC = NULL;
Alexandre Lision883719f2015-10-22 17:37:45 -0400849 }
Alexandre Lision266fca02015-09-28 14:47:05 -0400850
Alexandre Lision2db8f472015-07-22 15:05:46 -0400851 if (self.addToContactPopover != nullptr) {
852 [self.addToContactPopover performClose:self];
853 self.addToContactPopover = NULL;
854 }
Alexandre Lision883719f2015-10-22 17:37:45 -0400855
Alexandre Lision62005312016-01-28 15:55:16 -0500856 [self.transferButton setPressed:NO];
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500857 [self.addParticipantButton setState:NSOffState];
Alexandre Lision883719f2015-10-22 17:37:45 -0400858}
859
860- (void)popoverDidClose:(NSNotification *)notification
861{
862 [videoView setCallDelegate:self];
Alexandre Lision2db8f472015-07-22 15:05:46 -0400863}
864
865#pragma mark - ContactLinkedDelegate
866
867- (void)contactLinked
868{
869 if (self.addToContactPopover != nullptr) {
870 [self.addToContactPopover performClose:self];
871 self.addToContactPopover = NULL;
872 }
873}
874
Alexandre Lision58cab672015-06-09 15:25:40 -0400875#pragma mark - NSSplitViewDelegate
876
877/* 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.
878 */
879- (BOOL)splitView:(NSSplitView *)splitView shouldCollapseSubview:(NSView *)subview forDoubleClickOnDividerAtIndex:(NSInteger)dividerIndex;
880{
881 NSView* rightView = [[splitView subviews] objectAtIndex:1];
882 return ([subview isEqual:rightView]);
883}
884
885
886- (BOOL)splitView:(NSSplitView *)splitView canCollapseSubview:(NSView *)subview;
887{
888 NSView* rightView = [[splitView subviews] objectAtIndex:1];
889 return ([subview isEqual:rightView]);
890}
891
892
Alexandre Lisiona1eee3c2015-08-10 13:44:51 -0400893# pragma mark - CallnDelegate
Alexandre Lision58cab672015-06-09 15:25:40 -0400894
895- (void) callShouldToggleFullScreen
896{
897 if(self.splitView.isInFullScreenMode)
898 [self.splitView exitFullScreenModeWithOptions:nil];
899 else {
900 NSApplicationPresentationOptions options = NSApplicationPresentationDefault +NSApplicationPresentationAutoHideDock +
901 NSApplicationPresentationAutoHideMenuBar + NSApplicationPresentationAutoHideToolbar;
902 NSDictionary *opts = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithUnsignedInt:options],
903 NSFullScreenModeApplicationPresentationOptions, nil];
904
905 [self.splitView enterFullScreenMode:[NSScreen mainScreen] withOptions:opts];
906 }
907}
908
Alexandre Lisiona1eee3c2015-08-10 13:44:51 -0400909-(void) mouseIsMoving:(BOOL) move
910{
911 [[controlsPanel animator] setAlphaValue:move]; // fade out
912 [[headerContainer animator] setAlphaValue:move];
913}
914
Alexandre Lisionc5148052015-03-04 15:10:35 -0500915@end