blob: 249b96c66838a437606bd6c3c4e3305f6bdcbff7 [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 <call.h>
33#import <callmodel.h>
Alexandre Lision89edc6a2015-11-09 11:30:47 -050034#import <recentmodel.h>
Alexandre Lisionc5148052015-03-04 15:10:35 -050035#import <useractionmodel.h>
36#import <contactmethod.h>
Alexandre Lisionc5148052015-03-04 15:10:35 -050037#import <video/previewmanager.h>
38#import <video/renderer.h>
Alexandre Lision58cab672015-06-09 15:25:40 -040039#import <media/text.h>
Alexandre Lision2db8f472015-07-22 15:05:46 -040040#import <person.h>
Alexandre Lision210fe212016-01-27 11:15:13 -050041#import <globalinstances.h>
Alexandre Lisionc5148052015-03-04 15:10:35 -050042
Alexandre Lision62005312016-01-28 15:55:16 -050043#import "AppDelegate.h"
Alexandre Lisionf47a2562015-06-15 15:48:29 -040044#import "views/ITProgressIndicator.h"
Alexandre Lision74dd47f2015-04-14 13:47:42 -040045#import "views/CallView.h"
Alexandre Lision210fe212016-01-27 11:15:13 -050046#import "delegates/ImageManipulationDelegate.h"
Alexandre Lision2db8f472015-07-22 15:05:46 -040047#import "PersonLinkerVC.h"
Alexandre Lision16d9c0a2015-08-10 12:05:15 -040048#import "ChatVC.h"
Alexandre Lision883719f2015-10-22 17:37:45 -040049#import "BrokerVC.h"
Alexandre Lision4baba4c2016-02-11 13:00:57 -050050#import "views/IconButton.h"
Alexandre Lision74dd47f2015-04-14 13:47:42 -040051
Alexandre Lisionc5148052015-03-04 15:10:35 -050052@interface RendererConnectionsHolder : NSObject
53
54@property QMetaObject::Connection frameUpdated;
55@property QMetaObject::Connection started;
56@property QMetaObject::Connection stopped;
57
58@end
59
60@implementation RendererConnectionsHolder
61
62@end
63
Alexandre Lision2db8f472015-07-22 15:05:46 -040064@interface CurrentCallVC () <NSPopoverDelegate, ContactLinkedDelegate>
Alexandre Lisionc5148052015-03-04 15:10:35 -050065
Alexandre Lision210fe212016-01-27 11:15:13 -050066// Main container
67@property (unsafe_unretained) IBOutlet NSSplitView* splitView;
68
Alexandre Lision89edc6a2015-11-09 11:30:47 -050069// Header info
70@property (unsafe_unretained) IBOutlet NSView* headerContainer;
Alexandre Lision883719f2015-10-22 17:37:45 -040071@property (unsafe_unretained) IBOutlet NSTextField* personLabel;
72@property (unsafe_unretained) IBOutlet NSTextField* stateLabel;
Alexandre Lision89edc6a2015-11-09 11:30:47 -050073@property (unsafe_unretained) IBOutlet NSTextField* timeSpentLabel;
Alexandre Lision210fe212016-01-27 11:15:13 -050074@property (unsafe_unretained) IBOutlet NSImageView* personPhoto;
Alexandre Lision89edc6a2015-11-09 11:30:47 -050075
76// Call Controls
77@property (unsafe_unretained) IBOutlet NSView* controlsPanel;
Alexandre Lision62005312016-01-28 15:55:16 -050078
Alexandre Lision4baba4c2016-02-11 13:00:57 -050079@property QHash<int, IconButton*> actionHash;
80@property (unsafe_unretained) IBOutlet IconButton* holdOnOffButton;
81@property (unsafe_unretained) IBOutlet IconButton* hangUpButton;
82@property (unsafe_unretained) IBOutlet IconButton* recordOnOffButton;
83@property (unsafe_unretained) IBOutlet IconButton* pickUpButton;
84@property (unsafe_unretained) IBOutlet IconButton* muteAudioButton;
85@property (unsafe_unretained) IBOutlet IconButton* muteVideoButton;
86@property (unsafe_unretained) IBOutlet IconButton* addContactButton;
87@property (unsafe_unretained) IBOutlet IconButton* transferButton;
88@property (unsafe_unretained) IBOutlet IconButton* addParticipantButton;
89@property (unsafe_unretained) IBOutlet IconButton* chatButton;
Alexandre Lisiond18fa272015-06-15 11:18:03 -040090
Alexandre Lision62005312016-01-28 15:55:16 -050091@property (unsafe_unretained) IBOutlet NSView* advancedPanel;
92@property (unsafe_unretained) IBOutlet IconButton* advancedButton;
93
Alexandre Lisiond18fa272015-06-15 11:18:03 -040094
Alexandre Lision89edc6a2015-11-09 11:30:47 -050095// Join call panel
96@property (unsafe_unretained) IBOutlet NSView* joinPanel;
97@property (unsafe_unretained) IBOutlet NSButton* mergeCallsButton;
98
Alexandre Lision2db8f472015-07-22 15:05:46 -040099@property (strong) NSPopover* addToContactPopover;
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500100@property (strong) NSPopover* brokerPopoverVC;
Alexandre Lision883719f2015-10-22 17:37:45 -0400101@property (strong) IBOutlet ChatVC* chatVC;
Alexandre Lisionf23ec5a2015-07-16 11:24:06 -0400102
Alexandre Lision210fe212016-01-27 11:15:13 -0500103// Ringing call panel
104@property (unsafe_unretained) IBOutlet NSView* ringingPanel;
105@property (unsafe_unretained) IBOutlet NSImageView* incomingPersonPhoto;
106@property (unsafe_unretained) IBOutlet NSTextField* incomingDisplayName;
107
108// Outgoing call panel
109@property (unsafe_unretained) IBOutlet NSView* outgoingPanel;
110@property (unsafe_unretained) IBOutlet ITProgressIndicator *loadingIndicator;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500111
112// Video
Alexandre Lision58cab672015-06-09 15:25:40 -0400113@property (unsafe_unretained) IBOutlet CallView *videoView;
Alexandre Lision58cab672015-06-09 15:25:40 -0400114@property (unsafe_unretained) IBOutlet NSView *previewView;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500115
116@property RendererConnectionsHolder* previewHolder;
117@property RendererConnectionsHolder* videoHolder;
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400118@property QMetaObject::Connection videoStarted;
Alexandre Lision4d9905e2016-01-22 12:01:36 -0500119@property QMetaObject::Connection selectedCallChanged;
Alexandre Lisionb65c0272015-07-22 15:51:29 -0400120@property QMetaObject::Connection messageConnection;
121@property QMetaObject::Connection mediaAddedConnection;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500122
123@end
124
125@implementation CurrentCallVC
Alexandre Lision210fe212016-01-27 11:15:13 -0500126@synthesize personLabel, personPhoto, actionHash, stateLabel, holdOnOffButton, hangUpButton,
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500127 recordOnOffButton, pickUpButton, chatButton, transferButton, addParticipantButton, timeSpentLabel,
Alexandre Lision62005312016-01-28 15:55:16 -0500128 muteVideoButton, muteAudioButton, controlsPanel, advancedPanel, advancedButton, headerContainer, videoView, incomingDisplayName, incomingPersonPhoto,
Alexandre Lision210fe212016-01-27 11:15:13 -0500129 previewView, splitView, loadingIndicator, ringingPanel, joinPanel, outgoingPanel;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500130
131@synthesize previewHolder;
132@synthesize videoHolder;
133
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400134- (void) updateAllActions
Alexandre Lisionc5148052015-03-04 15:10:35 -0500135{
Alexandre Lisionf7e11142015-12-15 10:58:11 -0500136 for (int i = 0 ; i < CallModel::instance().userActionModel()->rowCount() ; i++) {
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400137 [self updateActionAtIndex:i];
138 }
139}
140
141- (void) updateActionAtIndex:(int) row
142{
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400143 const QModelIndex& idx = CallModel::instance().userActionModel()->index(row,0);
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400144 UserActionModel::Action action = qvariant_cast<UserActionModel::Action>(idx.data(UserActionModel::Role::ACTION));
Alexandre Lision4baba4c2016-02-11 13:00:57 -0500145 if (auto a = actionHash[(int) action]) {
Alexandre Lision266fca02015-09-28 14:47:05 -0400146 [a setHidden:!(idx.flags() & Qt::ItemIsEnabled)];
Alexandre Lision4baba4c2016-02-11 13:00:57 -0500147 [a setPressed:(idx.data(Qt::CheckStateRole) == Qt::Checked) ? YES : NO];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500148 }
149}
150
Alexandre Lision210fe212016-01-27 11:15:13 -0500151-(void) updateCall:(BOOL) firstRun
Alexandre Lisionc5148052015-03-04 15:10:35 -0500152{
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400153 QModelIndex callIdx = CallModel::instance().selectionModel()->currentIndex();
Alexandre Lision2db8f472015-07-22 15:05:46 -0400154 if (!callIdx.isValid()) {
155 return;
156 }
Alexandre Lision210fe212016-01-27 11:15:13 -0500157 auto current = CallModel::instance().selectedCall();
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500158
Alexandre Lision58cab672015-06-09 15:25:40 -0400159 [personLabel setStringValue:callIdx.data(Qt::DisplayRole).toString().toNSString()];
160 [timeSpentLabel setStringValue:callIdx.data((int)Call::Role::Length).toString().toNSString()];
Alexandre Lision57227772016-01-15 17:19:36 -0500161 [stateLabel setStringValue:callIdx.data((int)Call::Role::HumanStateName).toString().toNSString()];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500162
Alexandre Lision210fe212016-01-27 11:15:13 -0500163 if (firstRun) {
Alexandre Lision261f1b92016-04-04 12:35:34 -0400164 QVariant photo = GlobalInstances::pixmapManipulator().callPhoto(current, QSize(100,100));
Alexandre Lision210fe212016-01-27 11:15:13 -0500165 [personPhoto setImage:QtMac::toNSImage(qvariant_cast<QPixmap>(photo))];
166 }
167
Alexandre Lision2db8f472015-07-22 15:05:46 -0400168 auto contactmethod = qvariant_cast<Call*>(callIdx.data(static_cast<int>(Call::Role::Object)))->peerContactMethod();
169 BOOL shouldShow = (!contactmethod->contact() || contactmethod->contact()->isPlaceHolder());
170 [self.addContactButton setHidden:!shouldShow];
171
Alexandre Lision266fca02015-09-28 14:47:05 -0400172 // Default values for this views
Alexandre Lisionf47a2562015-06-15 15:48:29 -0400173 [loadingIndicator setHidden:YES];
Alexandre Lision266fca02015-09-28 14:47:05 -0400174 [videoView setShouldAcceptInteractions:NO];
Alexandre Lision210fe212016-01-27 11:15:13 -0500175 [ringingPanel setHidden:YES];
176 [outgoingPanel setHidden:YES];
177 [controlsPanel setHidden:NO];
178 [headerContainer setHidden:NO];
Alexandre Lision266fca02015-09-28 14:47:05 -0400179
Alexandre Lision210fe212016-01-27 11:15:13 -0500180 auto state = callIdx.data((int)Call::Role::State).value<Call::State>();
Alexandre Lisionc5148052015-03-04 15:10:35 -0500181 switch (state) {
Alexandre Lisione6dbf092015-04-11 17:19:35 -0400182 case Call::State::NEW:
Alexandre Lisione6dbf092015-04-11 17:19:35 -0400183 break;
Alexandre Lision22d615b2016-01-25 12:54:34 -0500184 case Call::State::DIALING:
Alexandre Lisionc5148052015-03-04 15:10:35 -0500185 case Call::State::INITIALIZATION:
Alexandre Lisionf47a2562015-06-15 15:48:29 -0400186 case Call::State::CONNECTED:
Alexandre Lisionf47a2562015-06-15 15:48:29 -0400187 [loadingIndicator setHidden:NO];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500188 case Call::State::RINGING:
Alexandre Lision210fe212016-01-27 11:15:13 -0500189 [controlsPanel setHidden:YES];
190 [outgoingPanel setHidden:NO];
191 break;
192 case Call::State::INCOMING:
193 [self setupIncoming:current];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500194 break;
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500195 case Call::State::CONFERENCE:
Alexandre Lision210fe212016-01-27 11:15:13 -0500196 [self setupConference:current];
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500197 break;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500198 case Call::State::CURRENT:
Alexandre Lision210fe212016-01-27 11:15:13 -0500199 [self setupCurrent:current];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500200 break;
201 case Call::State::HOLD:
Alexandre Lisionc5148052015-03-04 15:10:35 -0500202 break;
203 case Call::State::BUSY:
Alexandre Lisionc5148052015-03-04 15:10:35 -0500204 break;
205 case Call::State::OVER:
Alexandre Lision266fca02015-09-28 14:47:05 -0400206 case Call::State::FAILURE:
Alexandre Lision210fe212016-01-27 11:15:13 -0500207 [controlsPanel setHidden:YES];
208 [outgoingPanel setHidden:NO];
Alexandre Lisiona1eee3c2015-08-10 13:44:51 -0400209 if(self.splitView.isInFullScreenMode)
210 [self.splitView exitFullScreenModeWithOptions:nil];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500211 break;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500212 }
213
214}
215
Alexandre Lision210fe212016-01-27 11:15:13 -0500216-(void) setupIncoming:(Call*) c
217{
218 [ringingPanel setHidden:NO];
219 [controlsPanel setHidden:YES];
220 [headerContainer setHidden:YES];
221 QVariant photo = GlobalInstances::pixmapManipulator().callPhoto(c, QSize(100,100));
222 [incomingPersonPhoto setImage:QtMac::toNSImage(qvariant_cast<QPixmap>(photo))];
223 [incomingDisplayName setStringValue:c->formattedName().toNSString()];
224}
225
226-(void) setupCurrent:(Call*) c
227{
228 [joinPanel setHidden:!c->hasParentCall()];
229 [controlsPanel setHidden:c->hasParentCall()];
230 [videoView setShouldAcceptInteractions:YES];
231 [self.chatButton setHidden:NO];
232 [self.addParticipantButton setHidden:NO];
233 [self.transferButton setHidden:NO];
234}
235
236-(void) setupConference:(Call*) c
237{
238 [videoView setShouldAcceptInteractions:YES];
239 [self.chatButton setHidden:NO];
240 [joinPanel setHidden:YES];
241 [self.addParticipantButton setHidden:NO];
242 [self.transferButton setHidden:YES];
243}
244
245
Alexandre Lisionc5148052015-03-04 15:10:35 -0500246- (void)awakeFromNib
247{
248 NSLog(@"INIT CurrentCall VC");
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400249 [self.view setWantsLayer:YES];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500250
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400251 actionHash[ (int)UserActionModel::Action::ACCEPT] = pickUpButton;
252 actionHash[ (int)UserActionModel::Action::HOLD ] = holdOnOffButton;
253 actionHash[ (int)UserActionModel::Action::RECORD] = recordOnOffButton;
254 actionHash[ (int)UserActionModel::Action::HANGUP] = hangUpButton;
Alexandre Lisiond18fa272015-06-15 11:18:03 -0400255 actionHash[ (int)UserActionModel::Action::MUTE_AUDIO] = muteAudioButton;
256 actionHash[ (int)UserActionModel::Action::MUTE_VIDEO] = muteVideoButton;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500257
Alexandre Lisionc5148052015-03-04 15:10:35 -0500258 [videoView setWantsLayer:YES];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500259 [videoView.layer setBackgroundColor:[NSColor blackColor].CGColor];
260 [videoView.layer setFrame:videoView.frame];
261 [videoView.layer setContentsGravity:kCAGravityResizeAspect];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500262
Alexandre Lisionc5148052015-03-04 15:10:35 -0500263 [previewView setWantsLayer:YES];
Alexandre Lision22d615b2016-01-25 12:54:34 -0500264 [previewView.layer setBackgroundColor:[NSColor blackColor].CGColor];
265 [previewView.layer setContentsGravity:kCAGravityResizeAspectFill];
266 [previewView.layer setFrame:previewView.frame];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500267
268 [controlsPanel setWantsLayer:YES];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500269 [controlsPanel.layer setBackgroundColor:[NSColor clearColor].CGColor];
270 [controlsPanel.layer setFrame:controlsPanel.frame];
271
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400272 previewHolder = [[RendererConnectionsHolder alloc] init];
273 videoHolder = [[RendererConnectionsHolder alloc] init];
274
Alexandre Lisionf47a2562015-06-15 15:48:29 -0400275 [loadingIndicator setColor:[NSColor whiteColor]];
276 [loadingIndicator setNumberOfLines:100];
277 [loadingIndicator setWidthOfLine:2];
278 [loadingIndicator setLengthOfLine:2];
279 [loadingIndicator setInnerMargin:30];
280
Alexandre Lisiona1eee3c2015-08-10 13:44:51 -0400281 [self.videoView setCallDelegate:self];
Alexandre Lision58cab672015-06-09 15:25:40 -0400282
Alexandre Lisionc5148052015-03-04 15:10:35 -0500283 [self connect];
284}
285
286- (void) connect
287{
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500288 QObject::connect(RecentModel::instance().selectionModel(),
Alexandre Lisionc5148052015-03-04 15:10:35 -0500289 &QItemSelectionModel::currentChanged,
290 [=](const QModelIndex &current, const QModelIndex &previous) {
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500291 auto call = RecentModel::instance().getActiveCall(current);
292 if(!current.isValid() || !call) {
Alexandre Lisionc5148052015-03-04 15:10:35 -0500293 return;
294 }
Alexandre Lisionbb5dbcd2015-07-09 16:36:47 -0400295
Alexandre Lision4d9905e2016-01-22 12:01:36 -0500296 [self changeCallSelection:call];
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500297
Alexandre Lisionbb5dbcd2015-07-09 16:36:47 -0400298 if (call->state() == Call::State::HOLD) {
299 call << Call::Action::HOLD;
300 }
301
Alexandre Lision58cab672015-06-09 15:25:40 -0400302 [self collapseRightView];
Alexandre Lision210fe212016-01-27 11:15:13 -0500303 [self updateCall:YES];
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400304 [self updateAllActions];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500305 });
306
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400307 QObject::connect(CallModel::instance().userActionModel(),
Alexandre Lisionc5148052015-03-04 15:10:35 -0500308 &QAbstractItemModel::dataChanged,
309 [=](const QModelIndex &topLeft, const QModelIndex &bottomRight) {
Alexandre Lisionc5148052015-03-04 15:10:35 -0500310 const int first(topLeft.row()),last(bottomRight.row());
311 for(int i = first; i <= last;i++) {
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400312 [self updateActionAtIndex:i];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500313 }
314 });
315
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400316 QObject::connect(&CallModel::instance(),
Alexandre Lisionc5148052015-03-04 15:10:35 -0500317 &CallModel::callStateChanged,
318 [self](Call* c, Call::State state) {
Alexandre Lision57227772016-01-15 17:19:36 -0500319 auto current = CallModel::instance().selectionModel()->currentIndex();
320 if (!current.isValid())
321 [self animateOut];
322 else if (CallModel::instance().getIndex(c) == current) {
323 if (c->state() == Call::State::OVER) {
Alexandre Lision01cf5e32016-01-21 15:54:30 -0500324 RecentModel::instance().selectionModel()->clearCurrentIndex();
Alexandre Lision57227772016-01-15 17:19:36 -0500325 } else {
Alexandre Lision210fe212016-01-27 11:15:13 -0500326 [self updateCall:NO];
Alexandre Lision57227772016-01-15 17:19:36 -0500327 }
328 }
Alexandre Lision4d9905e2016-01-22 12:01:36 -0500329 });
330
331 QObject::connect(&CallModel::instance(),
332 &CallModel::incomingCall,
333 [self](Call* c) {
334 [self changeCallSelection:c];
Alexandre Lision4d9905e2016-01-22 12:01:36 -0500335 });
336}
337
338- (void) changeCallSelection:(Call* )c
339{
340 QObject::disconnect(self.selectedCallChanged);
341 CallModel::instance().selectCall(c);
342 self.selectedCallChanged = QObject::connect(CallModel::instance().selectedCall(),
343 &Call::changed,
344 [=]() {
Alexandre Lision210fe212016-01-27 11:15:13 -0500345 [self updateCall:NO];
Alexandre Lision4d9905e2016-01-22 12:01:36 -0500346 });
Alexandre Lisionc5148052015-03-04 15:10:35 -0500347}
348
Alexandre Lisionb65c0272015-07-22 15:51:29 -0400349- (void) monitorIncomingTextMessages:(Media::Text*) media
350{
351 /* connect to incoming chat messages to open the chat view */
352 QObject::disconnect(self.messageConnection);
353 self.messageConnection = QObject::connect(media,
354 &Media::Text::messageReceived,
355 [self] (const QMap<QString,QString>& m) {
356 if([[self splitView] isSubviewCollapsed:[[[self splitView] subviews] objectAtIndex: 1]])
357 [self uncollapseRightView];
358 });
359}
360
Alexandre Lisionc5148052015-03-04 15:10:35 -0500361-(void) connectVideoSignals
362{
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400363 QModelIndex idx = CallModel::instance().selectionModel()->currentIndex();
364 Call* call = CallModel::instance().getCall(idx);
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500365 QObject::disconnect(self.videoStarted);
Alexandre Lision58cab672015-06-09 15:25:40 -0400366 self.videoStarted = QObject::connect(call,
Alexandre Lisionc5148052015-03-04 15:10:35 -0500367 &Call::videoStarted,
368 [=](Video::Renderer* renderer) {
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400369 NSLog(@"Video started!");
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400370 [self connectVideoRenderer:renderer];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500371 });
372
373 if(call->videoRenderer())
374 {
Alexandre Lisionc5148052015-03-04 15:10:35 -0500375 [self connectVideoRenderer:call->videoRenderer()];
376 }
377
378 [self connectPreviewRenderer];
379
380}
381
382-(void) connectPreviewRenderer
383{
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400384 QObject::disconnect(previewHolder.frameUpdated);
385 QObject::disconnect(previewHolder.stopped);
386 QObject::disconnect(previewHolder.started);
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400387 previewHolder.started = QObject::connect(&Video::PreviewManager::instance(),
Alexandre Lisionc5148052015-03-04 15:10:35 -0500388 &Video::PreviewManager::previewStarted,
389 [=](Video::Renderer* renderer) {
Alexandre Lisionc5148052015-03-04 15:10:35 -0500390 QObject::disconnect(previewHolder.frameUpdated);
391 previewHolder.frameUpdated = QObject::connect(renderer,
392 &Video::Renderer::frameUpdated,
393 [=]() {
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400394 [self renderer:Video::PreviewManager::instance().previewRenderer()
Alexandre Lisionc5148052015-03-04 15:10:35 -0500395 renderFrameForView:previewView];
396 });
397 });
398
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400399 previewHolder.stopped = QObject::connect(&Video::PreviewManager::instance(),
Alexandre Lisionc5148052015-03-04 15:10:35 -0500400 &Video::PreviewManager::previewStopped,
401 [=](Video::Renderer* renderer) {
Alexandre Lisionc5148052015-03-04 15:10:35 -0500402 QObject::disconnect(previewHolder.frameUpdated);
403 [previewView.layer setContents:nil];
404 });
405
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400406 previewHolder.frameUpdated = QObject::connect(Video::PreviewManager::instance().previewRenderer(),
Alexandre Lisionc5148052015-03-04 15:10:35 -0500407 &Video::Renderer::frameUpdated,
408 [=]() {
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400409 [self renderer:Video::PreviewManager::instance().previewRenderer()
Alexandre Lisionc5148052015-03-04 15:10:35 -0500410 renderFrameForView:previewView];
411 });
412}
413
414-(void) connectVideoRenderer: (Video::Renderer*)renderer
415{
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400416 QObject::disconnect(videoHolder.frameUpdated);
417 QObject::disconnect(videoHolder.started);
418 QObject::disconnect(videoHolder.stopped);
Alexandre Lisionc5148052015-03-04 15:10:35 -0500419 videoHolder.frameUpdated = QObject::connect(renderer,
420 &Video::Renderer::frameUpdated,
421 [=]() {
422 [self renderer:renderer renderFrameForView:videoView];
423 });
424
425 videoHolder.started = QObject::connect(renderer,
426 &Video::Renderer::started,
427 [=]() {
Alexandre Lisionc5148052015-03-04 15:10:35 -0500428 QObject::disconnect(videoHolder.frameUpdated);
429 videoHolder.frameUpdated = QObject::connect(renderer,
430 &Video::Renderer::frameUpdated,
431 [=]() {
432 [self renderer:renderer renderFrameForView:videoView];
433 });
434 });
435
436 videoHolder.stopped = QObject::connect(renderer,
437 &Video::Renderer::stopped,
438 [=]() {
Alexandre Lisionc5148052015-03-04 15:10:35 -0500439 QObject::disconnect(videoHolder.frameUpdated);
440 [videoView.layer setContents:nil];
441 });
442}
443
444-(void) renderer: (Video::Renderer*)renderer renderFrameForView:(NSView*) view
445{
Alexandre Lisionc5148052015-03-04 15:10:35 -0500446 QSize res = renderer->size();
447
Alexandre Lision6731e132015-10-14 14:29:06 -0400448 auto frame_ptr = renderer->currentFrame();
449 auto frame_data = frame_ptr.ptr;
450 if (!frame_data)
451 return;
452
Alexandre Lisionc5148052015-03-04 15:10:35 -0500453
454 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
Alexandre Lision6731e132015-10-14 14:29:06 -0400455 CGContextRef newContext = CGBitmapContextCreate(frame_data,
Alexandre Lisionc5148052015-03-04 15:10:35 -0500456 res.width(),
457 res.height(),
458 8,
459 4*res.width(),
460 colorSpace,
461 kCGImageAlphaPremultipliedLast);
462
463
464 CGImageRef newImage = CGBitmapContextCreateImage(newContext);
465
466 /*We release some components*/
467 CGContextRelease(newContext);
468 CGColorSpaceRelease(colorSpace);
469
470 [CATransaction begin];
471 view.layer.contents = (__bridge id)newImage;
472 [CATransaction commit];
473
474 CFRelease(newImage);
475}
476
477- (void) initFrame
478{
479 [self.view setFrame:self.view.superview.bounds];
480 [self.view setHidden:YES];
481 self.view.layer.position = self.view.frame.origin;
Alexandre Lisionbb5dbcd2015-07-09 16:36:47 -0400482 [self collapseRightView];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500483}
484
485# pragma private IN/OUT animations
486
487-(void) animateIn
488{
Alexandre Lisionc5148052015-03-04 15:10:35 -0500489 CGRect frame = CGRectOffset(self.view.superview.bounds, -self.view.superview.bounds.size.width, 0);
490 [self.view setHidden:NO];
491
492 [CATransaction begin];
493 CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
494 [animation setFromValue:[NSValue valueWithPoint:frame.origin]];
495 [animation setToValue:[NSValue valueWithPoint:self.view.superview.bounds.origin]];
496 [animation setDuration:0.2f];
Alexandre Lision22d615b2016-01-25 12:54:34 -0500497 [animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500498 [CATransaction setCompletionBlock:^{
Alexandre Lisiona1eee3c2015-08-10 13:44:51 -0400499
500 // when call comes in we want to show the controls/header
501 [self mouseIsMoving:YES];
502
Alexandre Lisionc5148052015-03-04 15:10:35 -0500503 [self connectVideoSignals];
Alexandre Lisionb65c0272015-07-22 15:51:29 -0400504 /* check if text media is already present */
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400505 if(!CallModel::instance().selectedCall())
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400506 return;
Alexandre Lision21666f32015-09-22 17:04:36 -0400507
Alexandre Lision22d615b2016-01-25 12:54:34 -0500508 [loadingIndicator setAnimates:YES];
Alexandre Lision210fe212016-01-27 11:15:13 -0500509 [self updateCall:YES];
Alexandre Lision4d9905e2016-01-22 12:01:36 -0500510
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400511 if (CallModel::instance().selectedCall()->hasMedia(Media::Media::Type::TEXT, Media::Media::Direction::IN)) {
512 Media::Text *text = CallModel::instance().selectedCall()->firstMedia<Media::Text>(Media::Media::Direction::IN);
Alexandre Lisionb65c0272015-07-22 15:51:29 -0400513 [self monitorIncomingTextMessages:text];
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400514 } else if (CallModel::instance().selectedCall()->hasMedia(Media::Media::Type::TEXT, Media::Media::Direction::OUT)) {
515 Media::Text *text = CallModel::instance().selectedCall()->firstMedia<Media::Text>(Media::Media::Direction::OUT);
Alexandre Lisionb65c0272015-07-22 15:51:29 -0400516 [self monitorIncomingTextMessages:text];
517 } else {
518 /* monitor media for messaging text messaging */
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400519 self.mediaAddedConnection = QObject::connect(CallModel::instance().selectedCall(),
Alexandre Lisionb65c0272015-07-22 15:51:29 -0400520 &Call::mediaAdded,
521 [self] (Media::Media* media) {
522 if (media->type() == Media::Media::Type::TEXT) { [self monitorIncomingTextMessages:(Media::Text*)media];
523 QObject::disconnect(self.mediaAddedConnection);
524 }
525 });
526 }
Alexandre Lisionc5148052015-03-04 15:10:35 -0500527 }];
528 [self.view.layer addAnimation:animation forKey:animation.keyPath];
529
530 [CATransaction commit];
531}
532
533-(void) cleanUp
534{
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400535 QObject::disconnect(videoHolder.frameUpdated);
536 QObject::disconnect(videoHolder.started);
537 QObject::disconnect(videoHolder.stopped);
538 QObject::disconnect(previewHolder.frameUpdated);
539 QObject::disconnect(previewHolder.stopped);
540 QObject::disconnect(previewHolder.started);
Alexandre Lisionc5148052015-03-04 15:10:35 -0500541 [videoView.layer setContents:nil];
542 [previewView.layer setContents:nil];
Alexandre Lision883719f2015-10-22 17:37:45 -0400543
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500544 [_brokerPopoverVC performClose:self];
Alexandre Lision883719f2015-10-22 17:37:45 -0400545 [self.addToContactPopover performClose:self];
Alexandre Lision0e66aea2015-11-02 16:36:30 -0500546
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500547 [self.chatButton setHidden:YES];
548 [self.addParticipantButton setHidden:YES];
549 [self.transferButton setHidden:YES];
550
Alexandre Lision4baba4c2016-02-11 13:00:57 -0500551 [self.chatButton setPressed:NO];
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500552 [self.mergeCallsButton setState:NSOffState];
Alexandre Lision883719f2015-10-22 17:37:45 -0400553 [self collapseRightView];
Alexandre Lision57227772016-01-15 17:19:36 -0500554
555 [personLabel setStringValue:@""];
556 [timeSpentLabel setStringValue:@""];
557 [stateLabel setStringValue:@""];
558 [self.addContactButton setHidden:YES];
Alexandre Lision62005312016-01-28 15:55:16 -0500559
560 [advancedButton setPressed:NO];
561 [advancedPanel setHidden:YES];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500562}
563
564-(void) animateOut
565{
Alexandre Lisionc5148052015-03-04 15:10:35 -0500566 if(self.view.frame.origin.x < 0) {
Alexandre Lisionc5148052015-03-04 15:10:35 -0500567 return;
568 }
569
570 CGRect frame = CGRectOffset(self.view.frame, -self.view.frame.size.width, 0);
571 [CATransaction begin];
572 CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
573 [animation setFromValue:[NSValue valueWithPoint:self.view.frame.origin]];
574 [animation setToValue:[NSValue valueWithPoint:frame.origin]];
575 [animation setDuration:0.2f];
Alexandre Lision22d615b2016-01-25 12:54:34 -0500576 [animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500577
578 [CATransaction setCompletionBlock:^{
579 [self.view setHidden:YES];
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400580 // first make sure everything is disconnected
Alexandre Lisionc5148052015-03-04 15:10:35 -0500581 [self cleanUp];
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500582 if (RecentModel::instance().getActiveCall(RecentModel::instance().selectionModel()->currentIndex())) {
Alexandre Lisionc5148052015-03-04 15:10:35 -0500583 [self animateIn];
584 }
585 }];
586 [self.view.layer addAnimation:animation forKey:animation.keyPath];
Alexandre Lisiona1c6d752015-06-23 12:27:38 -0400587
588 [self.view.layer setPosition:frame.origin];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500589 [CATransaction commit];
590}
591
592/**
593 * Debug purpose
594 */
595-(void) dumpFrame:(CGRect) frame WithName:(NSString*) name
596{
597 NSLog(@"frame %@ : %f %f %f %f \n\n",name ,frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
598}
599
Alexandre Lision58cab672015-06-09 15:25:40 -0400600-(void)collapseRightView
601{
602 NSView *right = [[splitView subviews] objectAtIndex:1];
603 NSView *left = [[splitView subviews] objectAtIndex:0];
604 NSRect leftFrame = [left frame];
605 [right setHidden:YES];
606 [splitView display];
607}
Alexandre Lisionc5148052015-03-04 15:10:35 -0500608
Alexandre Lision58cab672015-06-09 15:25:40 -0400609-(void)uncollapseRightView
610{
611 NSView *left = [[splitView subviews] objectAtIndex:0];
612 NSView *right = [[splitView subviews] objectAtIndex:1];
613 [right setHidden:NO];
614
615 CGFloat dividerThickness = [splitView dividerThickness];
616
617 // get the different frames
618 NSRect leftFrame = [left frame];
619 NSRect rightFrame = [right frame];
620
621 leftFrame.size.width = (leftFrame.size.width - rightFrame.size.width - dividerThickness);
622 rightFrame.origin.x = leftFrame.size.width + dividerThickness;
623 [left setFrameSize:leftFrame.size];
624 [right setFrame:rightFrame];
625 [splitView display];
Alexandre Lision16d9c0a2015-08-10 12:05:15 -0400626
627 [self.chatVC takeFocus];
Alexandre Lision58cab672015-06-09 15:25:40 -0400628}
629
630
631#pragma mark - Button methods
632
Alexandre Lision2db8f472015-07-22 15:05:46 -0400633- (IBAction)addToContact:(NSButton*) sender {
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400634 auto contactmethod = CallModel::instance().getCall(CallModel::instance().selectionModel()->currentIndex())->peerContactMethod();
Alexandre Lision2db8f472015-07-22 15:05:46 -0400635
636 if (self.addToContactPopover != nullptr) {
637 [self.addToContactPopover performClose:self];
638 self.addToContactPopover = NULL;
639 } else if (!contactmethod->contact() || contactmethod->contact()->isPlaceHolder()) {
640 auto* editorVC = [[PersonLinkerVC alloc] initWithNibName:@"PersonLinker" bundle:nil];
641 [editorVC setMethodToLink:contactmethod];
642 [editorVC setContactLinkedDelegate:self];
643 self.addToContactPopover = [[NSPopover alloc] init];
644 [self.addToContactPopover setContentSize:editorVC.view.frame.size];
645 [self.addToContactPopover setContentViewController:editorVC];
646 [self.addToContactPopover setAnimates:YES];
647 [self.addToContactPopover setBehavior:NSPopoverBehaviorTransient];
648 [self.addToContactPopover setDelegate:self];
649
650 [self.addToContactPopover showRelativeToRect:sender.bounds ofView:sender preferredEdge:NSMaxXEdge];
651 }
Alexandre Lision883719f2015-10-22 17:37:45 -0400652
653 [videoView setCallDelegate:nil];
Alexandre Lision2db8f472015-07-22 15:05:46 -0400654}
655
Alexandre Lisionc5148052015-03-04 15:10:35 -0500656- (IBAction)hangUp:(id)sender {
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400657 CallModel::instance().getCall(CallModel::instance().selectionModel()->currentIndex()) << Call::Action::REFUSE;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500658}
659
660- (IBAction)accept:(id)sender {
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400661 CallModel::instance().getCall(CallModel::instance().selectionModel()->currentIndex()) << Call::Action::ACCEPT;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500662}
663
664- (IBAction)toggleRecording:(id)sender {
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400665 CallModel::instance().getCall(CallModel::instance().selectionModel()->currentIndex()) << Call::Action::RECORD_AUDIO;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500666}
667
668- (IBAction)toggleHold:(id)sender {
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400669 CallModel::instance().getCall(CallModel::instance().selectionModel()->currentIndex()) << Call::Action::HOLD;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500670}
671
Alexandre Lision62005312016-01-28 15:55:16 -0500672- (IBAction)toggleAdvancedControls:(id)sender {
673 [advancedButton setPressed:!advancedButton.isPressed];
674 [advancedPanel setHidden:![advancedButton isPressed]];
675}
676
677- (IBAction)showDialpad:(id)sender {
678 AppDelegate* appDelegate = (AppDelegate *)[[NSApplication sharedApplication] delegate];
679 [appDelegate showDialpad];
680}
681
Alexandre Lision58cab672015-06-09 15:25:40 -0400682-(IBAction)toggleChat:(id)sender;
683{
684 BOOL rightViewCollapsed = [[self splitView] isSubviewCollapsed:[[[self splitView] subviews] objectAtIndex: 1]];
685 if (rightViewCollapsed) {
686 [self uncollapseRightView];
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400687 CallModel::instance().getCall(CallModel::instance().selectionModel()->currentIndex())->addOutgoingMedia<Media::Text>();
Alexandre Lision58cab672015-06-09 15:25:40 -0400688 } else {
689 [self collapseRightView];
690 }
Alexandre Lision62005312016-01-28 15:55:16 -0500691 [chatButton setPressed:rightViewCollapsed];
Alexandre Lision58cab672015-06-09 15:25:40 -0400692}
693
Alexandre Lisiond18fa272015-06-15 11:18:03 -0400694- (IBAction)muteAudio:(id)sender
695{
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400696 UserActionModel* uam = CallModel::instance().userActionModel();
Alexandre Lisiond18fa272015-06-15 11:18:03 -0400697 uam << UserActionModel::Action::MUTE_AUDIO;
698}
699
700- (IBAction)muteVideo:(id)sender
701{
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400702 UserActionModel* uam = CallModel::instance().userActionModel();
Alexandre Lisiond18fa272015-06-15 11:18:03 -0400703 uam << UserActionModel::Action::MUTE_VIDEO;
704}
Alexandre Lision883719f2015-10-22 17:37:45 -0400705
706- (IBAction)toggleTransferView:(id)sender {
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500707 if (_brokerPopoverVC != nullptr) {
708 [_brokerPopoverVC performClose:self];
709 _brokerPopoverVC = NULL;
Alexandre Lision62005312016-01-28 15:55:16 -0500710 [self.transferButton setPressed:NO];
Alexandre Lision883719f2015-10-22 17:37:45 -0400711 } else {
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500712 auto* brokerVC = [[BrokerVC alloc] initWithMode:BrokerMode::TRANSFER];
713 _brokerPopoverVC = [[NSPopover alloc] init];
714 [_brokerPopoverVC setContentSize:brokerVC.view.frame.size];
715 [_brokerPopoverVC setContentViewController:brokerVC];
716 [_brokerPopoverVC setAnimates:YES];
717 [_brokerPopoverVC setBehavior:NSPopoverBehaviorTransient];
718 [_brokerPopoverVC setDelegate:self];
719 [_brokerPopoverVC showRelativeToRect:[sender bounds] ofView:sender preferredEdge:NSMinYEdge];
Alexandre Lision883719f2015-10-22 17:37:45 -0400720 [videoView setCallDelegate:nil];
721 }
Alexandre Lisionf23ec5a2015-07-16 11:24:06 -0400722}
Alexandre Lisiond18fa272015-06-15 11:18:03 -0400723
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500724- (IBAction)toggleAddParticipantView:(id)sender {
725 if (_brokerPopoverVC != nullptr) {
726 [_brokerPopoverVC performClose:self];
727 _brokerPopoverVC = NULL;
Alexandre Lision62005312016-01-28 15:55:16 -0500728 [self.addParticipantButton setPressed:NO];
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500729 } else {
730 auto* brokerVC = [[BrokerVC alloc] initWithMode:BrokerMode::CONFERENCE];
731 _brokerPopoverVC = [[NSPopover alloc] init];
732 [_brokerPopoverVC setContentSize:brokerVC.view.frame.size];
733 [_brokerPopoverVC setContentViewController:brokerVC];
734 [_brokerPopoverVC setAnimates:YES];
735 [_brokerPopoverVC setBehavior:NSPopoverBehaviorTransient];
736 [_brokerPopoverVC setDelegate:self];
737 [_brokerPopoverVC showRelativeToRect:[sender bounds] ofView:sender preferredEdge:NSMinYEdge];
738 [videoView setCallDelegate:nil];
739 }
740}
741
742/**
743 * Merge current call with its parent call
744 */
745- (IBAction)mergeCalls:(id)sender
746{
747 auto current = CallModel::instance().selectedCall();
748 current->joinToParent();
749}
750
Alexandre Lision2db8f472015-07-22 15:05:46 -0400751#pragma mark - NSPopOverDelegate
752
Alexandre Lision266fca02015-09-28 14:47:05 -0400753- (void)popoverWillClose:(NSNotification *)notification
754{
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500755 if (_brokerPopoverVC != nullptr) {
756 [_brokerPopoverVC performClose:self];
757 _brokerPopoverVC = NULL;
Alexandre Lision883719f2015-10-22 17:37:45 -0400758 }
Alexandre Lision266fca02015-09-28 14:47:05 -0400759
Alexandre Lision2db8f472015-07-22 15:05:46 -0400760 if (self.addToContactPopover != nullptr) {
761 [self.addToContactPopover performClose:self];
762 self.addToContactPopover = NULL;
763 }
Alexandre Lision883719f2015-10-22 17:37:45 -0400764
Alexandre Lision62005312016-01-28 15:55:16 -0500765 [self.addContactButton setPressed:NO];
766 [self.transferButton setPressed:NO];
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500767 [self.addParticipantButton setState:NSOffState];
Alexandre Lision883719f2015-10-22 17:37:45 -0400768}
769
770- (void)popoverDidClose:(NSNotification *)notification
771{
772 [videoView setCallDelegate:self];
Alexandre Lision2db8f472015-07-22 15:05:46 -0400773}
774
775#pragma mark - ContactLinkedDelegate
776
777- (void)contactLinked
778{
779 if (self.addToContactPopover != nullptr) {
780 [self.addToContactPopover performClose:self];
781 self.addToContactPopover = NULL;
782 }
783}
784
Alexandre Lision58cab672015-06-09 15:25:40 -0400785#pragma mark - NSSplitViewDelegate
786
787/* 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.
788 */
789- (BOOL)splitView:(NSSplitView *)splitView shouldCollapseSubview:(NSView *)subview forDoubleClickOnDividerAtIndex:(NSInteger)dividerIndex;
790{
791 NSView* rightView = [[splitView subviews] objectAtIndex:1];
792 return ([subview isEqual:rightView]);
793}
794
795
796- (BOOL)splitView:(NSSplitView *)splitView canCollapseSubview:(NSView *)subview;
797{
798 NSView* rightView = [[splitView subviews] objectAtIndex:1];
799 return ([subview isEqual:rightView]);
800}
801
802
Alexandre Lisiona1eee3c2015-08-10 13:44:51 -0400803# pragma mark - CallnDelegate
Alexandre Lision58cab672015-06-09 15:25:40 -0400804
805- (void) callShouldToggleFullScreen
806{
807 if(self.splitView.isInFullScreenMode)
808 [self.splitView exitFullScreenModeWithOptions:nil];
809 else {
810 NSApplicationPresentationOptions options = NSApplicationPresentationDefault +NSApplicationPresentationAutoHideDock +
811 NSApplicationPresentationAutoHideMenuBar + NSApplicationPresentationAutoHideToolbar;
812 NSDictionary *opts = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithUnsignedInt:options],
813 NSFullScreenModeApplicationPresentationOptions, nil];
814
815 [self.splitView enterFullScreenMode:[NSScreen mainScreen] withOptions:opts];
816 }
817}
818
Alexandre Lisiona1eee3c2015-08-10 13:44:51 -0400819-(void) mouseIsMoving:(BOOL) move
820{
821 [[controlsPanel animator] setAlphaValue:move]; // fade out
822 [[headerContainer animator] setAlphaValue:move];
823}
824
Alexandre Lisionc5148052015-03-04 15:10:35 -0500825@end