blob: 279d65c766a8f5b4de0042a5a5081b1ff94994aa [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 }
Kateryna Kostiukd76f6202018-09-11 17:15:28 -0400163 videoView.callId = callUid;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500164}
165
166- (void)awakeFromNib
167{
168 NSLog(@"INIT CurrentCall VC");
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400169 [self.view setWantsLayer:YES];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500170
Alexandre Lisionc5148052015-03-04 15:10:35 -0500171 [previewView setWantsLayer:YES];
Alexandre Lision22d615b2016-01-25 12:54:34 -0500172 [previewView.layer setBackgroundColor:[NSColor blackColor].CGColor];
173 [previewView.layer setContentsGravity:kCAGravityResizeAspectFill];
174 [previewView.layer setFrame:previewView.frame];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500175
176 [controlsPanel setWantsLayer:YES];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500177 [controlsPanel.layer setBackgroundColor:[NSColor clearColor].CGColor];
178 [controlsPanel.layer setFrame:controlsPanel.frame];
179
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400180 previewHolder = [[RendererConnectionsHolder alloc] init];
181 videoHolder = [[RendererConnectionsHolder alloc] init];
182
Alexandre Lisionf47a2562015-06-15 15:48:29 -0400183 [loadingIndicator setColor:[NSColor whiteColor]];
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400184 [loadingIndicator setNumberOfLines:200];
185 [loadingIndicator setWidthOfLine:4];
186 [loadingIndicator setLengthOfLine:4];
187 [loadingIndicator setInnerMargin:59];
Alexandre Lisionf47a2562015-06-15 15:48:29 -0400188
Alexandre Lisiona1eee3c2015-08-10 13:44:51 -0400189 [self.videoView setCallDelegate:self];
Kateryna Kostiuk1004caa2018-03-29 13:48:07 -0400190 CGColor* color = [[[NSColor blackColor] colorWithAlphaComponent:0.2] CGColor];
191 [headerContainer.layer setBackgroundColor:color];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500192}
193
Anthony Léonard66a050c2018-01-03 16:32:34 -0500194-(void) updateDurationLabel
195{
196 if (accountInfo_ != nil) {
197 auto* callModel = accountInfo_->callModel.get();
198 if (callModel->hasCall(callUid_)) {
199 auto& callStatus = callModel->getCall(callUid_).status;
200 if (callStatus != lrc::api::call::Status::ENDED &&
201 callStatus != lrc::api::call::Status::TERMINATING &&
202 callStatus != lrc::api::call::Status::INVALID) {
203 [timeSpentLabel setStringValue:@(callModel->getFormattedCallDuration(callUid_).c_str())];
204 return;
205 }
206 }
207 }
208
209 // If call is not running anymore or accountInfo_ is not set for any reason
210 // we stop the refresh loop
211 [refreshDurationTimer invalidate];
212 refreshDurationTimer = nil;
213 [timeSpentLabel setHidden:YES];
214}
215
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400216-(void) updateCall
Alexandre Lisionc5148052015-03-04 15:10:35 -0500217{
Olivier Soldano994971f2017-12-05 16:30:12 -0500218 if (accountInfo_ == nil)
219 return;
Alexandre Lisionbb5dbcd2015-07-09 16:36:47 -0400220
Olivier Soldano994971f2017-12-05 16:30:12 -0500221 auto* callModel = accountInfo_->callModel.get();
222 if (not callModel->hasCall(callUid_)) {
223 return;
224 }
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500225
Olivier Soldano994971f2017-12-05 16:30:12 -0500226 auto currentCall = callModel->getCall(callUid_);
227 NSLog(@"\n status %@ \n",@(lrc::api::call::to_string(currentCall.status).c_str()));
Anthony Léonard8ee26782018-01-05 10:23:04 -0500228 auto convIt = getConversationFromUid(convUid_, *accountInfo_->conversationModel);
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400229 if (convIt != accountInfo_->conversationModel->allFilteredConversations().end()) {
230 NSString* bestName = bestNameForConversation(*convIt, *accountInfo_->conversationModel);
231 [personLabel setStringValue:bestName];
232 [outgoingPersonLabel setStringValue:bestName];
233 NSString* ringID = bestIDForConversation(*convIt, *accountInfo_->conversationModel);
234 if([bestName isEqualToString:ringID]) {
235 ringID = @"";
236 }
237 [outgoingId setStringValue:ringID];
238 }
239
Anthony Léonard66a050c2018-01-03 16:32:34 -0500240 [timeSpentLabel setStringValue:@(callModel->getFormattedCallDuration(callUid_).c_str())];
Anthony Léonard66a050c2018-01-03 16:32:34 -0500241 if (refreshDurationTimer == nil)
242 refreshDurationTimer = [NSTimer scheduledTimerWithTimeInterval:1.0
243 target:self
244 selector:@selector(updateDurationLabel)
245 userInfo:nil
246 repeats:YES];
Olivier Soldano994971f2017-12-05 16:30:12 -0500247 [stateLabel setStringValue:@(to_string(currentCall.status).c_str())];
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400248 [outgoingStateLabel setStringValue:@(to_string(currentCall.status).c_str())];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500249
Olivier Soldano994971f2017-12-05 16:30:12 -0500250 // Default values for this views
251 [loadingIndicator setHidden:YES];
Olivier Soldano994971f2017-12-05 16:30:12 -0500252 [ringingPanel setHidden:YES];
253 [outgoingPanel setHidden:YES];
254 [controlsPanel setHidden:NO];
255 [headerContainer setHidden:NO];
Anthony Léonard4b0935f2017-12-26 12:05:22 -0500256 [chatButton setHidden:NO];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500257
Olivier Soldano994971f2017-12-05 16:30:12 -0500258 using Status = lrc::api::call::Status;
259 switch (currentCall.status) {
260 case Status::SEARCHING:
Olivier Soldano994971f2017-12-05 16:30:12 -0500261 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:
Olivier Soldano994971f2017-12-05 16:30:12 -0500285 case Status::INACTIVE:
286 case Status::IN_PROGRESS:
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400287 // change constraints (uncollapse avatar)
288 [self setupContactInfo:personPhoto];
Kateryna Kostiuk1004caa2018-03-29 13:48:07 -0400289 [timeSpentLabel setHidden:NO];
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400290 [outgoingPhoto setHidden:YES];
291 [headerContainer setHidden:NO];
292 break;
Olivier Soldano994971f2017-12-05 16:30:12 -0500293 case Status::CONNECTED:
Olivier Soldano994971f2017-12-05 16:30:12 -0500294 break;
295 case Status::ENDED:
296 case Status::TERMINATING:
297 case Status::INVALID:
298 [controlsPanel setHidden:YES];
299 [outgoingPanel setHidden:NO];
Andreas Traczykecdc4fa2018-03-22 16:11:47 -0400300 [self hideWithAnimation:false];
Olivier Soldano994971f2017-12-05 16:30:12 -0500301 break;
302 }
Alexandre Lision4d9905e2016-01-22 12:01:36 -0500303
Alexandre Lision4d9905e2016-01-22 12:01:36 -0500304}
305
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400306-(void) setupContactInfo:(NSImageView*)imageView
307{
308 auto* convModel = accountInfo_->conversationModel.get();
309 auto it = getConversationFromUid(convUid_, *convModel);
310 if (it != convModel->allFilteredConversations().end()) {
311 auto& imgManip = reinterpret_cast<Interfaces::ImageManipulationDelegate&>(GlobalInstances::pixmapManipulator());
312 QVariant photo = imgManip.conversationPhoto(*it, *accountInfo_, QSize(120, 120), NO);
313 [imageView setImage:QtMac::toNSImage(qvariant_cast<QPixmap>(photo))];
314 }
315}
316
Olivier Soldano994971f2017-12-05 16:30:12 -0500317-(void) setupIncoming:(const std::string&) callId
Alexandre Lision4d9905e2016-01-22 12:01:36 -0500318{
Olivier Soldano994971f2017-12-05 16:30:12 -0500319 if (accountInfo_ == nil)
320 return;
321
322 auto* callModel = accountInfo_->callModel.get();
323 if (not callModel->hasCall(callUid_)) {
324 return;
325 }
326
327 auto call = callModel->getCall(callUid_);
328 auto* convModel = accountInfo_->conversationModel.get();
329
330 [ringingPanel setHidden:NO];
331 [controlsPanel setHidden:YES];
332 [headerContainer setHidden:YES];
Anthony Léonard6f819752018-01-05 09:53:40 -0500333 auto it = getConversationFromUid(convUid_, *convModel);
Olivier Soldano994971f2017-12-05 16:30:12 -0500334 if (it != convModel->allFilteredConversations().end()) {
335 auto& imgManip = reinterpret_cast<Interfaces::ImageManipulationDelegate&>(GlobalInstances::pixmapManipulator());
336 QVariant photo = imgManip.conversationPhoto(*it, *accountInfo_);
337 [incomingPersonPhoto setImage:QtMac::toNSImage(qvariant_cast<QPixmap>(photo))];
Anthony Léonard8ee26782018-01-05 10:23:04 -0500338 [incomingDisplayName setStringValue:bestNameForConversation(*it, *convModel)];
Olivier Soldano994971f2017-12-05 16:30:12 -0500339 }
340}
341
342
343-(void) setupConference:(Call*) c
344{
345 [videoView setShouldAcceptInteractions:YES];
346 [self.chatButton setHidden:NO];
347 [joinPanel setHidden:YES];
348 [self.addParticipantButton setHidden:NO];
349 [self.transferButton setHidden:YES];
350}
351
352-(void)collapseRightView
353{
354 NSView *right = [[splitView subviews] objectAtIndex:1];
355 NSView *left = [[splitView subviews] objectAtIndex:0];
356 NSRect leftFrame = [left frame];
357 [right setHidden:YES];
358 [splitView display];
359}
360
361- (void) changeCallSelection:(std::string&)callUid
362{
363 if (accountInfo_ == nil)
364 return;
365
366 auto* callModel = accountInfo_->callModel.get();
367 if (not callModel->hasCall(callUid)) {
368 return;
369 }
370
Alexandre Lision4d9905e2016-01-22 12:01:36 -0500371 QObject::disconnect(self.selectedCallChanged);
Olivier Soldano994971f2017-12-05 16:30:12 -0500372 self.selectedCallChanged = QObject::connect(callModel,
373 &lrc::api::NewCallModel::callStatusChanged,
374 [self](const std::string callId) {
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400375 [self updateCall];
Alexandre Lision4d9905e2016-01-22 12:01:36 -0500376 });
Alexandre Lisionc5148052015-03-04 15:10:35 -0500377}
378
379-(void) connectVideoSignals
380{
Olivier Soldano994971f2017-12-05 16:30:12 -0500381 if (accountInfo_ == nil)
382 return;
383
384 auto* callModel = accountInfo_->callModel.get();
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500385 QObject::disconnect(self.videoStarted);
Olivier Soldano994971f2017-12-05 16:30:12 -0500386 self.videoStarted = QObject::connect(callModel,
387 &lrc::api::NewCallModel::remotePreviewStarted,
388 [self](const std::string& callId, Video::Renderer* renderer) {
389 NSLog(@"Video started!");
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -0400390 [videoView setLayer:[[CallLayer alloc] init]];
Kateryna Kostiuk1004caa2018-03-29 13:48:07 -0400391 [videoView setShouldAcceptInteractions:YES];
392 [self mouseIsMoving: NO];
Olivier Soldano994971f2017-12-05 16:30:12 -0500393 [self connectVideoRenderer:renderer];
394 });
Alexandre Lisionc5148052015-03-04 15:10:35 -0500395
Olivier Soldano994971f2017-12-05 16:30:12 -0500396 if (callModel->hasCall(callUid_)) {
397 if (auto renderer = callModel->getRenderer(callUid_)) {
398 QObject::disconnect(self.videoStarted);
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -0400399 [videoView setLayer:[[CallLayer alloc] init]];
Olivier Soldano994971f2017-12-05 16:30:12 -0500400 [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 Kostiukc17db8d2018-10-23 09:48:03 -0400470 [videoView setLayer:[CALayer layer]];
471 [videoView.layer setBackgroundColor:[[NSColor blackColor] CGColor]];
Kateryna Kostiuk1004caa2018-03-29 13:48:07 -0400472 [self mouseIsMoving: YES];
473 [videoView setShouldAcceptInteractions:NO];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500474 QObject::disconnect(videoHolder.frameUpdated);
Anthony Léonard14e7bf32017-06-08 08:13:16 -0400475 [(CallLayer*)videoView.layer setVideoRunning:NO];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500476 });
477}
478
Anthony Léonard14e7bf32017-06-08 08:13:16 -0400479-(void) renderer: (Video::Renderer*)renderer renderFrameForPreviewView:(NSView*) view
Alexandre Lisionc5148052015-03-04 15:10:35 -0500480{
Alexandre Lisionc5148052015-03-04 15:10:35 -0500481 QSize res = renderer->size();
482
Alexandre Lision6731e132015-10-14 14:29:06 -0400483 auto frame_ptr = renderer->currentFrame();
484 auto frame_data = frame_ptr.ptr;
485 if (!frame_data)
486 return;
487
Alexandre Lisionc5148052015-03-04 15:10:35 -0500488 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
Alexandre Lision6731e132015-10-14 14:29:06 -0400489 CGContextRef newContext = CGBitmapContextCreate(frame_data,
Alexandre Lisionc5148052015-03-04 15:10:35 -0500490 res.width(),
491 res.height(),
492 8,
493 4*res.width(),
494 colorSpace,
495 kCGImageAlphaPremultipliedLast);
496
497
498 CGImageRef newImage = CGBitmapContextCreateImage(newContext);
499
500 /*We release some components*/
501 CGContextRelease(newContext);
502 CGColorSpaceRelease(colorSpace);
503
504 [CATransaction begin];
505 view.layer.contents = (__bridge id)newImage;
506 [CATransaction commit];
507
508 CFRelease(newImage);
509}
510
Anthony Léonard14e7bf32017-06-08 08:13:16 -0400511-(void) renderer: (Video::Renderer*)renderer renderFrameForDistantView:(CallView*) view
512{
Anthony Léonard14e7bf32017-06-08 08:13:16 -0400513 auto frame_ptr = renderer->currentFrame();
514 if (!frame_ptr.ptr)
515 return;
516
517 CallLayer* callLayer = (CallLayer*) view.layer;
518
Anthony Léonarda9d7c8e2018-01-03 14:41:17 -0500519 [callLayer setCurrentFrame:std::move(frame_ptr)];
Anthony Léonard14e7bf32017-06-08 08:13:16 -0400520 [callLayer setVideoRunning:YES];
521}
522
Alexandre Lisionc5148052015-03-04 15:10:35 -0500523- (void) initFrame
524{
525 [self.view setFrame:self.view.superview.bounds];
526 [self.view setHidden:YES];
527 self.view.layer.position = self.view.frame.origin;
Alexandre Lisionbb5dbcd2015-07-09 16:36:47 -0400528 [self collapseRightView];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500529}
530
531# pragma private IN/OUT animations
532
Olivier Soldano994971f2017-12-05 16:30:12 -0500533-(void)uncollapseRightView
534{
535 NSView *left = [[splitView subviews] objectAtIndex:0];
536 NSView *right = [[splitView subviews] objectAtIndex:1];
537 [right setHidden:NO];
538
539 CGFloat dividerThickness = [splitView dividerThickness];
540
541 // get the different frames
542 NSRect leftFrame = [left frame];
543 NSRect rightFrame = [right frame];
544
545 leftFrame.size.width = (leftFrame.size.width - rightFrame.size.width - dividerThickness);
546 rightFrame.origin.x = leftFrame.size.width + dividerThickness;
547 [left setFrameSize:leftFrame.size];
548 [right setFrame:rightFrame];
549 [splitView display];
550
551 [self.chatVC takeFocus];
552}
553
Alexandre Lisionc5148052015-03-04 15:10:35 -0500554-(void) cleanUp
555{
Anthony Léonard5c287642018-02-21 15:54:19 -0500556 if(self.splitView.isInFullScreenMode)
557 [self.splitView exitFullScreenModeWithOptions:nil];
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400558 QObject::disconnect(videoHolder.frameUpdated);
559 QObject::disconnect(videoHolder.started);
560 QObject::disconnect(videoHolder.stopped);
561 QObject::disconnect(previewHolder.frameUpdated);
562 QObject::disconnect(previewHolder.stopped);
563 QObject::disconnect(previewHolder.started);
Anthony Léonardc0013bb2018-02-20 16:23:02 -0500564 QObject::disconnect(self.messageConnection);
Alexandre Lisionc5148052015-03-04 15:10:35 -0500565 [previewView.layer setContents:nil];
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -0400566 [videoView setLayer:[CALayer layer]];
567 [videoView.layer setBackgroundColor:[[NSColor blackColor] CGColor]];
Alexandre Lision883719f2015-10-22 17:37:45 -0400568
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500569 [_brokerPopoverVC performClose:self];
Alexandre Lision883719f2015-10-22 17:37:45 -0400570 [self.addToContactPopover performClose:self];
Alexandre Lision0e66aea2015-11-02 16:36:30 -0500571
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500572 [self.chatButton setHidden:YES];
573 [self.addParticipantButton setHidden:YES];
574 [self.transferButton setHidden:YES];
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400575 [self.qualityButton setHidden:YES];
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500576
Alexandre Lision4baba4c2016-02-11 13:00:57 -0500577 [self.chatButton setPressed:NO];
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500578 [self.mergeCallsButton setState:NSOffState];
Alexandre Lision883719f2015-10-22 17:37:45 -0400579 [self collapseRightView];
Alexandre Lision57227772016-01-15 17:19:36 -0500580
581 [personLabel setStringValue:@""];
582 [timeSpentLabel setStringValue:@""];
583 [stateLabel setStringValue:@""];
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400584
585 [outgoingPersonLabel setStringValue:@""];
586 [outgoingStateLabel setStringValue:@""];
Alexandre Lision62005312016-01-28 15:55:16 -0500587
588 [advancedButton setPressed:NO];
589 [advancedPanel setHidden:YES];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500590}
591
Andreas Traczykecdc4fa2018-03-22 16:11:47 -0400592-(void) setupCallView
593{
594 if (accountInfo_ == nil)
595 return;
596
597 auto* callModel = accountInfo_->callModel.get();
598 auto* convModel = accountInfo_->conversationModel.get();
599
600 // when call comes in we want to show the controls/header
Kateryna Kostiuk1004caa2018-03-29 13:48:07 -0400601 [self mouseIsMoving: YES];
602 [videoView setShouldAcceptInteractions: NO];
Andreas Traczykecdc4fa2018-03-22 16:11:47 -0400603
604 [self connectVideoSignals];
605 /* check if text media is already present */
606 if(not callModel->hasCall(callUid_))
607 return;
608
609 [loadingIndicator setAnimates:YES];
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400610 [self updateCall];
Andreas Traczykecdc4fa2018-03-22 16:11:47 -0400611
612 /* monitor media for messaging text messaging */
613 QObject::disconnect(self.messageConnection);
614 self.messageConnection = QObject::connect(convModel,
615 &lrc::api::ConversationModel::interactionStatusUpdated,
616 [self] (std::string convUid,
617 uint64_t msgId,
618 lrc::api::interaction::Info msg) {
619 if (msg.type == lrc::api::interaction::Type::TEXT) {
620 if(not [[self splitView] isSubviewCollapsed:[[[self splitView] subviews] objectAtIndex: 1]]){
621 return;
622 }
623 [self uncollapseRightView];
624 }
625 });
626}
627
628-(void) showWithAnimation:(BOOL)animate
629{
630 if (!animate) {
631 [self.view setHidden:NO];
632 [self setupCallView];
633 return;
634 }
635
636 CGRect frame = CGRectOffset(self.view.superview.bounds, -self.view.superview.bounds.size.width, 0);
637 [self.view setHidden:NO];
638
639 [CATransaction begin];
640 CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
641 [animation setFromValue:[NSValue valueWithPoint:frame.origin]];
642 [animation setToValue:[NSValue valueWithPoint:self.view.superview.bounds.origin]];
643 [animation setDuration:0.2f];
644 [animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]];
645 [CATransaction setCompletionBlock:^{
646 [self setupCallView];
647 }];
648
649 [self.view.layer addAnimation:animation forKey:animation.keyPath];
650 [CATransaction commit];
651}
652
653-(void) hideWithAnimation:(BOOL)animate
Alexandre Lisionc5148052015-03-04 15:10:35 -0500654{
Alexandre Lisionc5148052015-03-04 15:10:35 -0500655 if(self.view.frame.origin.x < 0) {
Alexandre Lisionc5148052015-03-04 15:10:35 -0500656 return;
657 }
658
Andreas Traczykecdc4fa2018-03-22 16:11:47 -0400659 if (!animate) {
Kateryna Kostiuk1004caa2018-03-29 13:48:07 -0400660 [self cleanUp];
Andreas Traczykecdc4fa2018-03-22 16:11:47 -0400661 [self.view setHidden:YES];
662 return;
663 }
664
Alexandre Lisionc5148052015-03-04 15:10:35 -0500665 CGRect frame = CGRectOffset(self.view.frame, -self.view.frame.size.width, 0);
666 [CATransaction begin];
667 CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
668 [animation setFromValue:[NSValue valueWithPoint:self.view.frame.origin]];
669 [animation setToValue:[NSValue valueWithPoint:frame.origin]];
670 [animation setDuration:0.2f];
Alexandre Lision22d615b2016-01-25 12:54:34 -0500671 [animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500672
673 [CATransaction setCompletionBlock:^{
674 [self.view setHidden:YES];
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400675 // first make sure everything is disconnected
Alexandre Lisionc5148052015-03-04 15:10:35 -0500676 [self cleanUp];
Olivier Soldano994971f2017-12-05 16:30:12 -0500677// if (currentCall_) {
678// [self animateIn];
679// }
Alexandre Lisionc5148052015-03-04 15:10:35 -0500680 }];
681 [self.view.layer addAnimation:animation forKey:animation.keyPath];
Alexandre Lisiona1c6d752015-06-23 12:27:38 -0400682
683 [self.view.layer setPosition:frame.origin];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500684 [CATransaction commit];
685}
686
687/**
688 * Debug purpose
689 */
690-(void) dumpFrame:(CGRect) frame WithName:(NSString*) name
691{
692 NSLog(@"frame %@ : %f %f %f %f \n\n",name ,frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
693}
694
Alexandre Lision58cab672015-06-09 15:25:40 -0400695#pragma mark - Button methods
696
Alexandre Lisionc5148052015-03-04 15:10:35 -0500697- (IBAction)hangUp:(id)sender {
Olivier Soldano994971f2017-12-05 16:30:12 -0500698 if (accountInfo_ == nil)
699 return;
700
701 auto* callModel = accountInfo_->callModel.get();
702
703 callModel->hangUp(callUid_);
Alexandre Lisionc5148052015-03-04 15:10:35 -0500704}
705
706- (IBAction)accept:(id)sender {
Olivier Soldano994971f2017-12-05 16:30:12 -0500707 if (accountInfo_ == nil)
708 return;
709
Anthony Léonardf584cc52018-01-19 12:00:19 -0500710 // If we accept a conversation with a non trusted contact, we first accept it
711 auto convIt = getConversationFromUid(convUid_, *accountInfo_->conversationModel.get());
712 if (convIt != accountInfo_->conversationModel->allFilteredConversations().end()) {
713 auto& contact = accountInfo_->contactModel->getContact(convIt->participants[0]);
714 if (contact.profileInfo.type == lrc::api::profile::Type::PENDING)
715 accountInfo_->conversationModel->makePermanent(convUid_);
716 }
717
Olivier Soldano994971f2017-12-05 16:30:12 -0500718 auto* callModel = accountInfo_->callModel.get();
719
720 callModel->accept(callUid_);
Alexandre Lisionc5148052015-03-04 15:10:35 -0500721}
722
723- (IBAction)toggleRecording:(id)sender {
Olivier Soldano994971f2017-12-05 16:30:12 -0500724 if (accountInfo_ == nil)
725 return;
726
727 auto* callModel = accountInfo_->callModel.get();
728
729 callModel->toggleAudioRecord(callUid_);
Kateryna Kostiuk54d76972018-06-07 15:45:07 -0400730 [recordOnOffButton setPressed:!recordOnOffButton.isPressed];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500731}
732
733- (IBAction)toggleHold:(id)sender {
Olivier Soldano994971f2017-12-05 16:30:12 -0500734 if (accountInfo_ == nil)
735 return;
736
737 auto* callModel = accountInfo_->callModel.get();
Kateryna Kostiuk54d76972018-06-07 15:45:07 -0400738 auto currentCall = callModel->getCall(callUid_);
739 if (currentCall.status != lrc::api::call::Status::PAUSED) {
740 holdOnOffButton.image = [NSImage imageNamed:@"ic_action_holdoff.png"];
741 } else {
742 holdOnOffButton.image = [NSImage imageNamed:@"ic_action_hold.png"];
743 }
Olivier Soldano994971f2017-12-05 16:30:12 -0500744
745 callModel->togglePause(callUid_);
Alexandre Lisionc5148052015-03-04 15:10:35 -0500746}
747
Alexandre Lision62005312016-01-28 15:55:16 -0500748- (IBAction)toggleAdvancedControls:(id)sender {
749 [advancedButton setPressed:!advancedButton.isPressed];
750 [advancedPanel setHidden:![advancedButton isPressed]];
751}
752
753- (IBAction)showDialpad:(id)sender {
754 AppDelegate* appDelegate = (AppDelegate *)[[NSApplication sharedApplication] delegate];
755 [appDelegate showDialpad];
756}
757
Alexandre Lision58cab672015-06-09 15:25:40 -0400758-(IBAction)toggleChat:(id)sender;
759{
760 BOOL rightViewCollapsed = [[self splitView] isSubviewCollapsed:[[[self splitView] subviews] objectAtIndex: 1]];
761 if (rightViewCollapsed) {
762 [self uncollapseRightView];
Alexandre Lision58cab672015-06-09 15:25:40 -0400763 } else {
764 [self collapseRightView];
765 }
Alexandre Lision62005312016-01-28 15:55:16 -0500766 [chatButton setPressed:rightViewCollapsed];
Alexandre Lision58cab672015-06-09 15:25:40 -0400767}
768
Alexandre Lisiond18fa272015-06-15 11:18:03 -0400769- (IBAction)muteAudio:(id)sender
770{
Olivier Soldano994971f2017-12-05 16:30:12 -0500771 if (accountInfo_ == nil)
772 return;
773
774 auto* callModel = accountInfo_->callModel.get();
Kateryna Kostiuk54d76972018-06-07 15:45:07 -0400775 auto currentCall = callModel->getCall(callUid_);
776 if (currentCall.audioMuted) {
777 muteAudioButton.image = [NSImage imageNamed:@"ic_action_audio.png"];
778 } else {
779 muteAudioButton.image = [NSImage imageNamed:@"ic_action_mute_audio.png"];
780 }
Olivier Soldano994971f2017-12-05 16:30:12 -0500781 callModel->toggleMedia(callUid_, lrc::api::NewCallModel::Media::AUDIO);
Alexandre Lisiond18fa272015-06-15 11:18:03 -0400782}
783
784- (IBAction)muteVideo:(id)sender
785{
Olivier Soldano994971f2017-12-05 16:30:12 -0500786 if (accountInfo_ == nil)
787 return;
Olivier Soldano994971f2017-12-05 16:30:12 -0500788 auto* callModel = accountInfo_->callModel.get();
Kateryna Kostiuk54d76972018-06-07 15:45:07 -0400789 auto currentCall = callModel->getCall(callUid_);
790 if(!currentCall.isAudioOnly) {
791 if (currentCall.videoMuted) {
792 muteVideoButton.image = [NSImage imageNamed:@"ic_action_video.png"];
793 } else {
794 muteVideoButton.image = [NSImage imageNamed:@"ic_action_mute_video.png"];
795 }
796 }
Olivier Soldano994971f2017-12-05 16:30:12 -0500797 callModel->toggleMedia(callUid_, lrc::api::NewCallModel::Media::VIDEO);
Alexandre Lisiond18fa272015-06-15 11:18:03 -0400798}
Alexandre Lision883719f2015-10-22 17:37:45 -0400799
800- (IBAction)toggleTransferView:(id)sender {
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500801 if (_brokerPopoverVC != nullptr) {
802 [_brokerPopoverVC performClose:self];
803 _brokerPopoverVC = NULL;
Alexandre Lision62005312016-01-28 15:55:16 -0500804 [self.transferButton setPressed:NO];
Alexandre Lision883719f2015-10-22 17:37:45 -0400805 } else {
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500806 auto* brokerVC = [[BrokerVC alloc] initWithMode:BrokerMode::TRANSFER];
807 _brokerPopoverVC = [[NSPopover alloc] init];
808 [_brokerPopoverVC setContentSize:brokerVC.view.frame.size];
809 [_brokerPopoverVC setContentViewController:brokerVC];
810 [_brokerPopoverVC setAnimates:YES];
811 [_brokerPopoverVC setBehavior:NSPopoverBehaviorTransient];
812 [_brokerPopoverVC setDelegate:self];
813 [_brokerPopoverVC showRelativeToRect:[sender bounds] ofView:sender preferredEdge:NSMinYEdge];
Alexandre Lision883719f2015-10-22 17:37:45 -0400814 [videoView setCallDelegate:nil];
815 }
Alexandre Lisionf23ec5a2015-07-16 11:24:06 -0400816}
Alexandre Lisiond18fa272015-06-15 11:18:03 -0400817
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500818- (IBAction)toggleAddParticipantView:(id)sender {
819 if (_brokerPopoverVC != nullptr) {
820 [_brokerPopoverVC performClose:self];
821 _brokerPopoverVC = NULL;
Alexandre Lision62005312016-01-28 15:55:16 -0500822 [self.addParticipantButton setPressed:NO];
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500823 } else {
824 auto* brokerVC = [[BrokerVC alloc] initWithMode:BrokerMode::CONFERENCE];
825 _brokerPopoverVC = [[NSPopover alloc] init];
826 [_brokerPopoverVC setContentSize:brokerVC.view.frame.size];
827 [_brokerPopoverVC setContentViewController:brokerVC];
828 [_brokerPopoverVC setAnimates:YES];
829 [_brokerPopoverVC setBehavior:NSPopoverBehaviorTransient];
830 [_brokerPopoverVC setDelegate:self];
831 [_brokerPopoverVC showRelativeToRect:[sender bounds] ofView:sender preferredEdge:NSMinYEdge];
832 [videoView setCallDelegate:nil];
833 }
834}
835
836/**
837 * Merge current call with its parent call
838 */
839- (IBAction)mergeCalls:(id)sender
840{
Olivier Soldano994971f2017-12-05 16:30:12 -0500841// auto current = CallModel::instance().selectedCall();
842// current->joinToParent();
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500843}
844
Alexandre Lision2db8f472015-07-22 15:05:46 -0400845#pragma mark - NSPopOverDelegate
846
Alexandre Lision266fca02015-09-28 14:47:05 -0400847- (void)popoverWillClose:(NSNotification *)notification
848{
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500849 if (_brokerPopoverVC != nullptr) {
850 [_brokerPopoverVC performClose:self];
851 _brokerPopoverVC = NULL;
Alexandre Lision883719f2015-10-22 17:37:45 -0400852 }
Alexandre Lision266fca02015-09-28 14:47:05 -0400853
Alexandre Lision2db8f472015-07-22 15:05:46 -0400854 if (self.addToContactPopover != nullptr) {
855 [self.addToContactPopover performClose:self];
856 self.addToContactPopover = NULL;
857 }
Alexandre Lision883719f2015-10-22 17:37:45 -0400858
Alexandre Lision62005312016-01-28 15:55:16 -0500859 [self.transferButton setPressed:NO];
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500860 [self.addParticipantButton setState:NSOffState];
Alexandre Lision883719f2015-10-22 17:37:45 -0400861}
862
863- (void)popoverDidClose:(NSNotification *)notification
864{
865 [videoView setCallDelegate:self];
Alexandre Lision2db8f472015-07-22 15:05:46 -0400866}
867
868#pragma mark - ContactLinkedDelegate
869
870- (void)contactLinked
871{
872 if (self.addToContactPopover != nullptr) {
873 [self.addToContactPopover performClose:self];
874 self.addToContactPopover = NULL;
875 }
876}
877
Alexandre Lision58cab672015-06-09 15:25:40 -0400878#pragma mark - NSSplitViewDelegate
879
880/* 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.
881 */
882- (BOOL)splitView:(NSSplitView *)splitView shouldCollapseSubview:(NSView *)subview forDoubleClickOnDividerAtIndex:(NSInteger)dividerIndex;
883{
884 NSView* rightView = [[splitView subviews] objectAtIndex:1];
885 return ([subview isEqual:rightView]);
886}
887
888
889- (BOOL)splitView:(NSSplitView *)splitView canCollapseSubview:(NSView *)subview;
890{
891 NSView* rightView = [[splitView subviews] objectAtIndex:1];
892 return ([subview isEqual:rightView]);
893}
894
895
Alexandre Lisiona1eee3c2015-08-10 13:44:51 -0400896# pragma mark - CallnDelegate
Alexandre Lision58cab672015-06-09 15:25:40 -0400897
898- (void) callShouldToggleFullScreen
899{
900 if(self.splitView.isInFullScreenMode)
901 [self.splitView exitFullScreenModeWithOptions:nil];
902 else {
903 NSApplicationPresentationOptions options = NSApplicationPresentationDefault +NSApplicationPresentationAutoHideDock +
904 NSApplicationPresentationAutoHideMenuBar + NSApplicationPresentationAutoHideToolbar;
905 NSDictionary *opts = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithUnsignedInt:options],
906 NSFullScreenModeApplicationPresentationOptions, nil];
907
908 [self.splitView enterFullScreenMode:[NSScreen mainScreen] withOptions:opts];
909 }
910}
911
Alexandre Lisiona1eee3c2015-08-10 13:44:51 -0400912-(void) mouseIsMoving:(BOOL) move
913{
914 [[controlsPanel animator] setAlphaValue:move]; // fade out
915 [[headerContainer animator] setAlphaValue:move];
916}
917
Alexandre Lisionc5148052015-03-04 15:10:35 -0500918@end