CurrentCallVC.mm 39.7 KB
Newer Older
1
/*
Alexandre Lision's avatar
Alexandre Lision committed
2
 *  Copyright (C) 2015-2016 Savoir-faire Linux Inc.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
 *  Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
 */
#import "CurrentCallVC.h"

#import <QuartzCore/QuartzCore.h>

Alexandre Lision's avatar
Alexandre Lision committed
23 24 25 26 27 28 29 30 31
///Qt
#import <QMimeData>
#import <QtMacExtras/qmacfunctions.h>
#import <QtCore/qabstractitemmodel.h>
#import <QItemSelectionModel>
#import <QItemSelection>
#import <QPixmap>

///LRC
32 33
#import <video/previewmanager.h>
#import <video/renderer.h>
34 35 36
#import <api/newcallmodel.h>
#import <api/call.h>
#import <api/conversationmodel.h>
Alexandre Lision's avatar
Alexandre Lision committed
37
#import <globalinstances.h>
38

Alexandre Lision's avatar
Alexandre Lision committed
39
#import "AppDelegate.h"
40
#import "views/ITProgressIndicator.h"
Alexandre Lision's avatar
Alexandre Lision committed
41
#import "views/CallView.h"
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
42
#import "views/NSColor+RingTheme.h"
Alexandre Lision's avatar
Alexandre Lision committed
43
#import "delegates/ImageManipulationDelegate.h"
44
#import "PersonLinkerVC.h"
Alexandre Lision's avatar
Alexandre Lision committed
45
#import "ChatVC.h"
Alexandre Lision's avatar
Alexandre Lision committed
46
#import "BrokerVC.h"
47
#import "views/IconButton.h"
48
#import "views/CallLayer.h"
49
#import "utils.h"
Alexandre Lision's avatar
Alexandre Lision committed
50

51 52 53 54 55 56 57 58 59 60 61 62
@interface RendererConnectionsHolder : NSObject

@property QMetaObject::Connection frameUpdated;
@property QMetaObject::Connection started;
@property QMetaObject::Connection stopped;

@end

@implementation RendererConnectionsHolder

@end

63 64 65 66
@interface CurrentCallVC () <NSPopoverDelegate, ContactLinkedDelegate> {
    std::string convUid_;
    std::string callUid_;
    const lrc::api::account::Info *accountInfo_;
67
    NSTimer* refreshDurationTimer;
68
}
69

Alexandre Lision's avatar
Alexandre Lision committed
70 71
// Main container
@property (unsafe_unretained) IBOutlet NSSplitView* splitView;
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
72
@property (unsafe_unretained) IBOutlet NSView* backgroundImage;
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
73
@property (unsafe_unretained) IBOutlet NSBox* bluerBackgroundEffect;
Alexandre Lision's avatar
Alexandre Lision committed
74

75 76
// Header info
@property (unsafe_unretained) IBOutlet NSView* headerContainer;
Alexandre Lision's avatar
Alexandre Lision committed
77 78
@property (unsafe_unretained) IBOutlet NSTextField* personLabel;
@property (unsafe_unretained) IBOutlet NSTextField* stateLabel;
79
@property (unsafe_unretained) IBOutlet NSTextField* timeSpentLabel;
Alexandre Lision's avatar
Alexandre Lision committed
80
@property (unsafe_unretained) IBOutlet NSImageView* personPhoto;
81

Andreas Traczyk's avatar
Andreas Traczyk committed
82 83 84 85 86
@property (unsafe_unretained) IBOutlet NSImageView* outgoingPhoto;
@property (unsafe_unretained) IBOutlet NSTextField* outgoingPersonLabel;
@property (unsafe_unretained) IBOutlet NSTextField* outgoingStateLabel;
@property (unsafe_unretained) IBOutlet NSTextField* outgoingId;

87 88
// Call Controls
@property (unsafe_unretained) IBOutlet NSView* controlsPanel;
Alexandre Lision's avatar
Alexandre Lision committed
89

90 91 92 93 94 95 96 97 98
@property (unsafe_unretained) IBOutlet IconButton* holdOnOffButton;
@property (unsafe_unretained) IBOutlet IconButton* hangUpButton;
@property (unsafe_unretained) IBOutlet IconButton* recordOnOffButton;
@property (unsafe_unretained) IBOutlet IconButton* pickUpButton;
@property (unsafe_unretained) IBOutlet IconButton* muteAudioButton;
@property (unsafe_unretained) IBOutlet IconButton* muteVideoButton;
@property (unsafe_unretained) IBOutlet IconButton* transferButton;
@property (unsafe_unretained) IBOutlet IconButton* addParticipantButton;
@property (unsafe_unretained) IBOutlet IconButton* chatButton;
Andreas Traczyk's avatar
Andreas Traczyk committed
99
@property (unsafe_unretained) IBOutlet IconButton* qualityButton;
100

Alexandre Lision's avatar
Alexandre Lision committed
101 102
@property (unsafe_unretained) IBOutlet NSView* advancedPanel;
@property (unsafe_unretained) IBOutlet IconButton* advancedButton;
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
103
@property (assign) IBOutlet NSLayoutConstraint* callRecordButtonMarginLeft;
104

105
@property (strong) NSPopover* addToContactPopover;
106
@property (strong) NSPopover* brokerPopoverVC;
Alexandre Lision's avatar
Alexandre Lision committed
107
@property (strong) IBOutlet ChatVC* chatVC;
108

Alexandre Lision's avatar
Alexandre Lision committed
109 110 111 112 113 114 115 116
// Ringing call panel
@property (unsafe_unretained) IBOutlet NSView* ringingPanel;
@property (unsafe_unretained) IBOutlet NSImageView* incomingPersonPhoto;
@property (unsafe_unretained) IBOutlet NSTextField* incomingDisplayName;

// Outgoing call panel
@property (unsafe_unretained) IBOutlet NSView* outgoingPanel;
@property (unsafe_unretained) IBOutlet ITProgressIndicator *loadingIndicator;
117

Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
118 119 120 121 122 123 124
// audio only view
@property (unsafe_unretained) IBOutlet NSView* audioCallView;
@property (unsafe_unretained) IBOutlet NSImageView* audioCallPhoto;
@property (unsafe_unretained) IBOutlet NSTextField* audioCallTime;
@property (unsafe_unretained) IBOutlet NSTextField* audioCallPersonLabel;
@property (unsafe_unretained) IBOutlet NSTextField* audioCallPersonId;

125
// Video
Alexandre Lision's avatar
Alexandre Lision committed
126 127
@property (unsafe_unretained) IBOutlet CallView *videoView;
@property (unsafe_unretained) IBOutlet NSView *previewView;
128 129 130

@property RendererConnectionsHolder* previewHolder;
@property RendererConnectionsHolder* videoHolder;
131
@property QMetaObject::Connection videoStarted;
Alexandre Lision's avatar
Alexandre Lision committed
132
@property QMetaObject::Connection selectedCallChanged;
133 134
@property QMetaObject::Connection messageConnection;
@property QMetaObject::Connection mediaAddedConnection;
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
135
@property QMetaObject::Connection profileUpdatedConnection;
136 137 138 139

@end

@implementation CurrentCallVC
140
@synthesize personLabel, personPhoto, stateLabel, holdOnOffButton, hangUpButton,
141
            recordOnOffButton, pickUpButton, chatButton, transferButton, addParticipantButton, timeSpentLabel,
142
            muteVideoButton, muteAudioButton, controlsPanel, advancedPanel, advancedButton, headerContainer, videoView,
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
143 144 145
            incomingDisplayName, incomingPersonPhoto, previewView, splitView, loadingIndicator, ringingPanel,
            outgoingPanel, outgoingPersonLabel, outgoingStateLabel, outgoingPhoto, outgoingId,
            callRecordButtonMarginLeft, audioCallView, audioCallPhoto, audioCallTime, audioCallPersonLabel, audioCallPersonId, backgroundImage, bluerBackgroundEffect;
146 147 148 149

@synthesize previewHolder;
@synthesize videoHolder;

150 151 152
-(void) setCurrentCall:(const std::string&)callUid
          conversation:(const std::string&)convUid
               account:(const lrc::api::account::Info*)account;
153
{
154 155 156 157 158 159 160 161
    if(account == nil)
        return;

    auto* callModel = account->callModel.get();

    if (not callModel->hasCall(callUid)){
        callUid_.clear();
        return;
162
    }
163 164 165
    callUid_ = callUid;
    convUid_ = convUid;
    accountInfo_ = account;
Anthony Léonard's avatar
Anthony Léonard committed
166
    [self.chatVC setConversationUid:convUid model:account->conversationModel.get()];
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
167
    auto currentCall = callModel->getCall(callUid_);
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
168 169 170
    [muteVideoButton setHidden: currentCall.isAudioOnly ? YES: NO];
    callRecordButtonMarginLeft.constant = currentCall.isAudioOnly ? -40.0f: 10.0f;
    [previewView setHidden: YES];
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
171
    videoView.callId = callUid;
172 173
}

Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
- (void) ensureLayoutForCallStatus:(lrc::api::call::Status) status {
    using Status = lrc::api::call::Status;
    switch (status) {
        case Status::IN_PROGRESS:
            if (![videoView.layer isKindOfClass:[CallLayer class]]) {
                [videoView setLayer:[[CallLayer alloc] init]];
            }
            break;
        default:
            if ([videoView.layer isKindOfClass:[CallLayer class]]) {
                [videoView setLayer:[CALayer layer]];
                [videoView.layer setBackgroundColor:[[NSColor blackColor] CGColor]];
            }
            break;
    }
    holdOnOffButton.image = status == lrc::api::call::Status::PAUSED ?
    [NSImage imageNamed:@"ic_action_holdoff.png"] : [NSImage imageNamed:@"ic_action_hold.png"];
}

193
- (void)awakeFromNib
194
{
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
    NSLog(@"INIT CurrentCall VC");
    [self.view setWantsLayer:YES];

    [previewView setWantsLayer:YES];
    [previewView.layer setBackgroundColor:[NSColor blackColor].CGColor];
    [previewView.layer setContentsGravity:kCAGravityResizeAspectFill];
    [previewView.layer setFrame:previewView.frame];

    [controlsPanel setWantsLayer:YES];
    [controlsPanel.layer setBackgroundColor:[NSColor clearColor].CGColor];
    [controlsPanel.layer setFrame:controlsPanel.frame];

    previewHolder = [[RendererConnectionsHolder alloc] init];
    videoHolder = [[RendererConnectionsHolder alloc] init];

    [loadingIndicator setColor:[NSColor whiteColor]];
Andreas Traczyk's avatar
Andreas Traczyk committed
211 212 213 214
    [loadingIndicator setNumberOfLines:200];
    [loadingIndicator setWidthOfLine:4];
    [loadingIndicator setLengthOfLine:4];
    [loadingIndicator setInnerMargin:59];
215 216

    [self.videoView setCallDelegate:self];
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
217 218
    CGColor* color = [[[NSColor blackColor] colorWithAlphaComponent:0.2] CGColor];
    [headerContainer.layer setBackgroundColor:color];
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
219 220 221 222
    [bluerBackgroundEffect setWantsLayer:YES];
    bluerBackgroundEffect.alphaValue = 0.6;
    [audioCallView setWantsLayer:YES];
    [audioCallView.layer setBackgroundColor: [[NSColor clearColor] CGColor]];
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
223 224
    [backgroundImage setWantsLayer: YES];
    backgroundImage.layer.contentsGravity = kCAGravityResizeAspectFill;
225 226
}

227 228 229 230 231 232 233 234 235
-(void) updateDurationLabel
{
    if (accountInfo_ != nil) {
        auto* callModel = accountInfo_->callModel.get();
        if (callModel->hasCall(callUid_)) {
            auto& callStatus = callModel->getCall(callUid_).status;
            if (callStatus != lrc::api::call::Status::ENDED &&
                callStatus != lrc::api::call::Status::TERMINATING &&
                callStatus != lrc::api::call::Status::INVALID) {
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
236 237 238 239 240
                if(callModel->getCall(callUid_).isAudioOnly) {
                    [audioCallTime setStringValue:@(callModel->getFormattedCallDuration(callUid_).c_str())];
                } else {
                    [timeSpentLabel setStringValue:@(callModel->getFormattedCallDuration(callUid_).c_str())];
                }
241 242 243 244 245 246 247 248 249 250
                return;
            }
        }
    }

    // If call is not running anymore or accountInfo_ is not set for any reason
    // we stop the refresh loop
    [refreshDurationTimer invalidate];
    refreshDurationTimer = nil;
    [timeSpentLabel setHidden:YES];
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
251
    [audioCallView setHidden:YES];
252 253
}

Andreas Traczyk's avatar
Andreas Traczyk committed
254
-(void) updateCall
255
{
256 257 258 259 260
    if (accountInfo_ == nil)
        return;

    auto* callModel = accountInfo_->callModel.get();
    if (not callModel->hasCall(callUid_)) {
261 262
        return;
    }
263

264 265
    auto currentCall = callModel->getCall(callUid_);
    NSLog(@"\n status %@ \n",@(lrc::api::call::to_string(currentCall.status).c_str()));
266
    auto convIt = getConversationFromUid(convUid_, *accountInfo_->conversationModel);
Andreas Traczyk's avatar
Andreas Traczyk committed
267 268 269 270
    if (convIt != accountInfo_->conversationModel->allFilteredConversations().end()) {
        NSString* bestName = bestNameForConversation(*convIt, *accountInfo_->conversationModel);
        [personLabel setStringValue:bestName];
        [outgoingPersonLabel setStringValue:bestName];
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
271
        [audioCallPersonLabel setStringValue:bestName];
Andreas Traczyk's avatar
Andreas Traczyk committed
272 273 274 275 276
        NSString* ringID = bestIDForConversation(*convIt, *accountInfo_->conversationModel);
        if([bestName isEqualToString:ringID]) {
            ringID = @"";
        }
        [outgoingId setStringValue:ringID];
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
277
        [audioCallPersonId setStringValue:ringID];
Andreas Traczyk's avatar
Andreas Traczyk committed
278 279
    }

280
    [timeSpentLabel setStringValue:@(callModel->getFormattedCallDuration(callUid_).c_str())];
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
281
    [audioCallTime setStringValue:@(callModel->getFormattedCallDuration(callUid_).c_str())];
282 283 284 285 286 287
    if (refreshDurationTimer == nil)
        refreshDurationTimer = [NSTimer scheduledTimerWithTimeInterval:1.0
                                                                target:self
                                                              selector:@selector(updateDurationLabel)
                                                              userInfo:nil
                                                               repeats:YES];
288
    [stateLabel setStringValue:@(to_string(currentCall.status).c_str())];
Andreas Traczyk's avatar
Andreas Traczyk committed
289
    [outgoingStateLabel setStringValue:@(to_string(currentCall.status).c_str())];
Alexandre Lision's avatar
Alexandre Lision committed
290

Alexandre Lision's avatar
Alexandre Lision committed
291
    // Default values for this views
292
    [loadingIndicator setHidden:YES];
Alexandre Lision's avatar
Alexandre Lision committed
293 294 295 296
    [ringingPanel setHidden:YES];
    [outgoingPanel setHidden:YES];
    [controlsPanel setHidden:NO];
    [headerContainer setHidden:NO];
Anthony Léonard's avatar
Anthony Léonard committed
297
    [chatButton setHidden:NO];
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
298
    [self setBackground];
Alexandre Lision's avatar
Alexandre Lision committed
299

300
    using Status = lrc::api::call::Status;
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
301
    [self ensureLayoutForCallStatus:currentCall.status];
302 303 304
    switch (currentCall.status) {
        case Status::SEARCHING:
        case Status::CONNECTING:
Andreas Traczyk's avatar
Andreas Traczyk committed
305 306 307 308
            [headerContainer setHidden:YES];
            [outgoingPanel setHidden:NO];
            [outgoingPhoto setHidden:NO];
            [self setupContactInfo:outgoingPhoto];
309
            [loadingIndicator setHidden:NO];
Andreas Traczyk's avatar
Andreas Traczyk committed
310
            [controlsPanel setHidden:YES];
311
            break;
312
        case Status::INCOMING_RINGING:
Andreas Traczyk's avatar
Andreas Traczyk committed
313
            [outgoingPhoto setHidden:YES];
314 315 316
            [controlsPanel setHidden:YES];
            [outgoingPanel setHidden:YES];
            [self setupIncoming:callUid_];
317
            break;
318 319 320
        case Status::OUTGOING_RINGING:
            [controlsPanel setHidden:YES];
            [outgoingPanel setHidden:NO];
Andreas Traczyk's avatar
Andreas Traczyk committed
321 322
            [loadingIndicator setHidden:NO];
            [headerContainer setHidden:YES];
323
            break;
Andreas Traczyk's avatar
Andreas Traczyk committed
324 325 326
        /*case Status::CONFERENCE:
            [self setupConference:currentCall];
            break;*/
327 328 329
        case Status::PAUSED:
        case Status::INACTIVE:
        case Status::IN_PROGRESS:
Andreas Traczyk's avatar
Andreas Traczyk committed
330
            // change constraints (uncollapse avatar)
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
331 332 333 334 335
            if(currentCall.isAudioOnly) {
                [self setUpAudioOnlyView];
            } else {
                [self setUpVideoCallView];
            }
Andreas Traczyk's avatar
Andreas Traczyk committed
336
            break;
337
        case Status::CONNECTED:
338
            break;
339 340 341
        case Status::ENDED:
        case Status::TERMINATING:
        case Status::INVALID:
Alexandre Lision's avatar
Alexandre Lision committed
342 343
            [controlsPanel setHidden:YES];
            [outgoingPanel setHidden:NO];
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
344
            [self cleanUp];
345
            [self hideWithAnimation:false];
346 347 348 349
            break;
    }
}

Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366
-(void) setUpVideoCallView {
    [self setupContactInfo:personPhoto];
    [timeSpentLabel setHidden:NO];
    [outgoingPhoto setHidden:YES];
    [headerContainer setHidden:NO];
    [previewView setHidden: NO];
    [bluerBackgroundEffect setHidden:YES];
    [backgroundImage setHidden:YES];
}

-(void) setUpAudioOnlyView {
    [audioCallView setHidden:NO];
    [headerContainer setHidden:YES];
    [audioCallPhoto setImage: [self getContactImageOfSize:120.0 withDefaultAvatar:YES]];
}

-(void) setBackground {
Andreas Traczyk's avatar
Andreas Traczyk committed
367 368
    auto* convModel = accountInfo_->conversationModel.get();
    auto it = getConversationFromUid(convUid_, *convModel);
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
369 370
    NSImage *image= [self getContactImageOfSize:120.0 withDefaultAvatar:NO];
    if(image) {
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
371 372 373 374 375
        CIImage * ciImage = [[CIImage alloc] initWithData:[image TIFFRepresentation]];
        CIContext *context = [[CIContext alloc] init];
        CIFilter *clamp = [CIFilter filterWithName:@"CIAffineClamp"];
        [clamp setValue:[NSAffineTransform transform] forKey:@"inputTransform"];
        [clamp setValue:ciImage forKey: kCIInputImageKey];
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
376 377
        CIFilter* bluerFilter = [CIFilter filterWithName:@"CIGaussianBlur"];
        [bluerFilter setDefaults];
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
378 379 380 381 382 383 384
        [bluerFilter setValue:[NSNumber numberWithFloat: 9] forKey:@"inputRadius"];
        [bluerFilter setValue:[clamp valueForKey:kCIOutputImageKey] forKey: kCIInputImageKey];
        CIImage *result = [bluerFilter valueForKey:kCIOutputImageKey];
        CGRect extent = [result extent];
        CGImageRef cgImage = [context createCGImage:result fromRect: [ciImage extent]];
        NSImage *bluredImage = [[NSImage alloc] initWithCGImage:cgImage size:NSSizeFromCGSize(CGSizeMake(image.size.width, image.size.height))];
        backgroundImage.layer.contents = bluredImage;
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
385 386 387 388 389 390 391
        [backgroundImage setHidden:NO];
    } else {
        [bluerBackgroundEffect setFillColor:[NSColor ringDarkGrey]];
        [backgroundImage setHidden:YES];
    }
}

Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
392
-(NSImage *) getContactImageOfSize: (double) size withDefaultAvatar:(BOOL) shouldDrawDefault {
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
393 394 395 396 397 398
    auto* convModel = accountInfo_->conversationModel.get();
    auto convIt = getConversationFromUid(convUid_, *convModel);
    if (convIt == convModel->allFilteredConversations().end()) {
        return nil;
    }
    if(shouldDrawDefault) {
Andreas Traczyk's avatar
Andreas Traczyk committed
399
        auto& imgManip = reinterpret_cast<Interfaces::ImageManipulationDelegate&>(GlobalInstances::pixmapManipulator());
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
400 401
        QVariant photo = imgManip.conversationPhoto(*convIt, *accountInfo_, QSize(size, size), NO);
        return QtMac::toNSImage(qvariant_cast<QPixmap>(photo));
Andreas Traczyk's avatar
Andreas Traczyk committed
402
    }
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
403 404 405 406 407 408 409 410 411
    auto contact = accountInfo_->contactModel->getContact(convIt->participants[0]);
    NSData *imageData = [[NSData alloc] initWithBase64EncodedString:@(contact.profileInfo.avatar.c_str()) options:NSDataBase64DecodingIgnoreUnknownCharacters];
    return [[NSImage alloc] initWithData:imageData];
}


-(void) setupContactInfo:(NSImageView*)imageView
{
    [imageView setImage: [self getContactImageOfSize:120.0 withDefaultAvatar:YES]];
Andreas Traczyk's avatar
Andreas Traczyk committed
412 413
}

414
-(void) setupIncoming:(const std::string&) callId
Alexandre Lision's avatar
Alexandre Lision committed
415
{
416 417 418 419 420 421 422 423 424 425 426
    if (accountInfo_ == nil)
        return;

    auto* callModel = accountInfo_->callModel.get();
    if (not callModel->hasCall(callUid_)) {
        return;
    }

    auto call = callModel->getCall(callUid_);
    auto* convModel = accountInfo_->conversationModel.get();

Alexandre Lision's avatar
Alexandre Lision committed
427 428 429
    [ringingPanel setHidden:NO];
    [controlsPanel setHidden:YES];
    [headerContainer setHidden:YES];
430
    auto it = getConversationFromUid(convUid_, *convModel);
431
    if (it != convModel->allFilteredConversations().end()) {
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
432
        [incomingPersonPhoto setImage: [self getContactImageOfSize:120.0 withDefaultAvatar:YES]];
433
        [incomingDisplayName setStringValue:bestNameForConversation(*it, *convModel)];
434
    }
Alexandre Lision's avatar
Alexandre Lision committed
435 436 437 438 439 440 441 442 443 444 445
}


-(void) setupConference:(Call*) c
{
    [videoView setShouldAcceptInteractions:YES];
    [self.chatButton setHidden:NO];
    [self.addParticipantButton setHidden:NO];
    [self.transferButton setHidden:YES];
}

446
-(void)collapseRightView
447
{
448 449 450 451 452
    NSView *right = [[splitView subviews] objectAtIndex:1];
    NSView *left  = [[splitView subviews] objectAtIndex:0];
    NSRect leftFrame = [left frame];
    [right setHidden:YES];
    [splitView display];
453 454
}

455
- (void) changeCallSelection:(std::string&)callUid
456
{
457 458
    if (accountInfo_ == nil)
        return;
Alexandre Lision's avatar
Alexandre Lision committed
459

460 461 462 463
    auto* callModel = accountInfo_->callModel.get();
    if (not callModel->hasCall(callUid)) {
        return;
    }
Alexandre Lision's avatar
Alexandre Lision committed
464 465

    QObject::disconnect(self.selectedCallChanged);
466 467 468
    self.selectedCallChanged = QObject::connect(callModel,
                                                &lrc::api::NewCallModel::callStatusChanged,
                                                [self](const std::string callId) {
Andreas Traczyk's avatar
Andreas Traczyk committed
469
                                                    [self updateCall];
Alexandre Lision's avatar
Alexandre Lision committed
470
                                                });
471 472 473 474
}

-(void) connectVideoSignals
{
475 476
    if (accountInfo_ == nil)
        return;
477

478 479 480 481 482
    auto* callModel = accountInfo_->callModel.get();
    QObject::disconnect(self.videoStarted);
    self.videoStarted = QObject::connect(callModel,
                                         &lrc::api::NewCallModel::remotePreviewStarted,
                                         [self](const std::string& callId, Video::Renderer* renderer) {
483
                                             [videoView setLayer:[[CallLayer alloc] init]];
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
484 485
                                             [videoView setShouldAcceptInteractions:YES];
                                             [self mouseIsMoving: NO];
486 487 488 489 490 491 492 493
                                             [self connectVideoRenderer:renderer];
                                         });

    if (callModel->hasCall(callUid_)) {
        if (auto renderer = callModel->getRenderer(callUid_)) {
            QObject::disconnect(self.videoStarted);
            [self connectVideoRenderer: renderer];
        }
494 495 496 497 498 499 500
    }
    [self connectPreviewRenderer];

}

-(void) connectPreviewRenderer
{
501 502 503
    QObject::disconnect(previewHolder.frameUpdated);
    QObject::disconnect(previewHolder.stopped);
    QObject::disconnect(previewHolder.started);
Alexandre Lision's avatar
Alexandre Lision committed
504
    previewHolder.started = QObject::connect(&Video::PreviewManager::instance(),
505 506 507 508 509 510
                     &Video::PreviewManager::previewStarted,
                     [=](Video::Renderer* renderer) {
                         QObject::disconnect(previewHolder.frameUpdated);
                         previewHolder.frameUpdated = QObject::connect(renderer,
                                                                       &Video::Renderer::frameUpdated,
                                                                       [=]() {
Alexandre Lision's avatar
Alexandre Lision committed
511
                                                                           [self renderer:Video::PreviewManager::instance().previewRenderer()
512
                                                                       renderFrameForPreviewView:previewView];
513 514 515
                                                                       });
                     });

Alexandre Lision's avatar
Alexandre Lision committed
516
    previewHolder.stopped = QObject::connect(&Video::PreviewManager::instance(),
517 518
                     &Video::PreviewManager::previewStopped,
                     [=](Video::Renderer* renderer) {
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
519
                        QObject::disconnect(previewHolder.frameUpdated);
520 521 522
                        [previewView.layer setContents:nil];
                     });

Alexandre Lision's avatar
Alexandre Lision committed
523
    previewHolder.frameUpdated = QObject::connect(Video::PreviewManager::instance().previewRenderer(),
524 525
                                                 &Video::Renderer::frameUpdated,
                                                 [=]() {
Alexandre Lision's avatar
Alexandre Lision committed
526
                                                     [self renderer:Video::PreviewManager::instance().previewRenderer()
527
                                                            renderFrameForPreviewView:previewView];
528 529 530 531 532
                                                 });
}

-(void) connectVideoRenderer: (Video::Renderer*)renderer
{
533 534 535
    QObject::disconnect(videoHolder.frameUpdated);
    QObject::disconnect(videoHolder.started);
    QObject::disconnect(videoHolder.stopped);
536 537 538 539

    if(renderer == nil)
        return;

540 541 542
    videoHolder.frameUpdated = QObject::connect(renderer,
                     &Video::Renderer::frameUpdated,
                     [=]() {
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
543 544 545
                         if(!renderer->isRendering()) {
                             return;
                         }
546
                         [self renderer:renderer renderFrameForDistantView:videoView];
547 548 549 550 551
                     });

    videoHolder.started = QObject::connect(renderer,
                     &Video::Renderer::started,
                     [=]() {
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
552 553 554
                         if (![videoView.layer isKindOfClass:[CallLayer class]]) {
                             [videoView setLayer:[[CallLayer alloc] init]];
                         }
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
555 556
                         [self mouseIsMoving: NO];
                         [videoView setShouldAcceptInteractions:YES];
557 558 559 560
                         QObject::disconnect(videoHolder.frameUpdated);
                         videoHolder.frameUpdated = QObject::connect(renderer,
                                                                     &Video::Renderer::frameUpdated,
                                                                     [=]() {
561
                                                                         [self renderer:renderer renderFrameForDistantView:videoView];
562 563 564 565 566 567
                                                                     });
                     });

    videoHolder.stopped = QObject::connect(renderer,
                     &Video::Renderer::stopped,
                     [=]() {
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
568
                         [(CallLayer*)videoView.layer setVideoRunning:NO];
569 570
                         [videoView setLayer:[CALayer layer]];
                         [videoView.layer setBackgroundColor:[[NSColor blackColor] CGColor]];
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
571 572
                         [self mouseIsMoving: YES];
                         [videoView setShouldAcceptInteractions:NO];
573 574 575 576
                         QObject::disconnect(videoHolder.frameUpdated);
                     });
}

577
-(void) renderer: (Video::Renderer*)renderer renderFrameForPreviewView:(NSView*) view
578 579 580
{
    QSize res = renderer->size();

581 582 583 584 585
    auto frame_ptr = renderer->currentFrame();
    auto frame_data = frame_ptr.ptr;
    if (!frame_data)
        return;

586
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
587
    CGContextRef newContext = CGBitmapContextCreate(frame_data,
588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608
                                                    res.width(),
                                                    res.height(),
                                                    8,
                                                    4*res.width(),
                                                    colorSpace,
                                                    kCGImageAlphaPremultipliedLast);


    CGImageRef newImage = CGBitmapContextCreateImage(newContext);

    /*We release some components*/
    CGContextRelease(newContext);
    CGColorSpaceRelease(colorSpace);

    [CATransaction begin];
    view.layer.contents = (__bridge id)newImage;
    [CATransaction commit];

    CFRelease(newImage);
}

609 610 611 612 613 614 615
-(void) renderer: (Video::Renderer*)renderer renderFrameForDistantView:(CallView*) view
{
    auto frame_ptr = renderer->currentFrame();
    if (!frame_ptr.ptr)
        return;

    CallLayer* callLayer = (CallLayer*) view.layer;
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
616 617 618 619
    if ([callLayer respondsToSelector:@selector(setCurrentFrame:)]) {
        [callLayer setCurrentFrame:std::move(frame_ptr)];
        [callLayer setVideoRunning:YES];
    }
620 621
}

622 623 624 625 626
- (void) initFrame
{
    [self.view setFrame:self.view.superview.bounds];
    [self.view setHidden:YES];
    self.view.layer.position = self.view.frame.origin;
627
    [self collapseRightView];
628 629 630 631
}

# pragma private IN/OUT animations

632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652
-(void)uncollapseRightView
{
    NSView *left  = [[splitView subviews] objectAtIndex:0];
    NSView *right = [[splitView subviews] objectAtIndex:1];
    [right setHidden:NO];

    CGFloat dividerThickness = [splitView dividerThickness];

    // get the different frames
    NSRect leftFrame = [left frame];
    NSRect rightFrame = [right frame];

    leftFrame.size.width = (leftFrame.size.width - rightFrame.size.width - dividerThickness);
    rightFrame.origin.x = leftFrame.size.width + dividerThickness;
    [left setFrameSize:leftFrame.size];
    [right setFrame:rightFrame];
    [splitView display];

    [self.chatVC takeFocus];
}

653 654
-(void) cleanUp
{
655 656
    if(self.splitView.isInFullScreenMode)
        [self.splitView exitFullScreenModeWithOptions:nil];
657 658 659 660 661 662
    QObject::disconnect(videoHolder.frameUpdated);
    QObject::disconnect(videoHolder.started);
    QObject::disconnect(videoHolder.stopped);
    QObject::disconnect(previewHolder.frameUpdated);
    QObject::disconnect(previewHolder.stopped);
    QObject::disconnect(previewHolder.started);
663
    QObject::disconnect(self.messageConnection);
664
    [previewView.layer setContents:nil];
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
665
    [previewView setHidden: YES];
666 667
    [videoView setLayer:[CALayer layer]];
    [videoView.layer setBackgroundColor:[[NSColor blackColor] CGColor]];
Alexandre Lision's avatar
Alexandre Lision committed
668

669
    [self.chatButton setHidden:YES];
670
    [self.chatButton setPressed:NO];
Alexandre Lision's avatar
Alexandre Lision committed
671
    [self collapseRightView];
Alexandre Lision's avatar
Alexandre Lision committed
672 673 674 675

    [personLabel setStringValue:@""];
    [timeSpentLabel setStringValue:@""];
    [stateLabel setStringValue:@""];
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
676 677 678 679 680 681 682 683 684 685
    //audio view
    [audioCallTime setStringValue:@""];
    [audioCallPersonId setStringValue:@""];
    [audioCallPersonLabel setStringValue:@""];
    [audioCallView setHidden:YES];
    [audioCallPhoto setImage:nil];
    //background view
    [bluerBackgroundEffect setHidden:NO];
    [backgroundImage setHidden:NO];
    //outgoing view
Andreas Traczyk's avatar
Andreas Traczyk committed
686 687
    [outgoingPersonLabel setStringValue:@""];
    [outgoingStateLabel setStringValue:@""];
688 689
}

690 691 692 693 694 695 696 697 698
-(void) setupCallView
{
    if (accountInfo_ == nil)
        return;

    auto* callModel = accountInfo_->callModel.get();
    auto* convModel = accountInfo_->conversationModel.get();

    // when call comes in we want to show the controls/header
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
699 700
    [self mouseIsMoving: YES];
    [videoView setShouldAcceptInteractions: NO];
701 702 703 704 705 706 707

    [self connectVideoSignals];
    /* check if text media is already present */
    if(not callModel->hasCall(callUid_))
        return;

    [loadingIndicator setAnimates:YES];
Andreas Traczyk's avatar
Andreas Traczyk committed
708
    [self updateCall];
709 710 711 712 713 714 715 716 717 718 719 720 721 722 723

    /* monitor media for messaging text messaging */
    QObject::disconnect(self.messageConnection);
    self.messageConnection = QObject::connect(convModel,
                                              &lrc::api::ConversationModel::interactionStatusUpdated,
                                              [self] (std::string convUid,
                                                      uint64_t msgId,
                                                      lrc::api::interaction::Info msg) {
                                                  if (msg.type == lrc::api::interaction::Type::TEXT) {
                                                      if(not [[self splitView] isSubviewCollapsed:[[[self splitView] subviews] objectAtIndex: 1]]){
                                                          return;
                                                      }
                                                      [self uncollapseRightView];
                                                  }
                                              });
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742
    //monitor for updated profile
    QObject::disconnect(self.profileUpdatedConnection);
    self.profileUpdatedConnection =
    QObject::connect(accountInfo_->contactModel.get(),
                     &lrc::api::ContactModel::contactAdded,
                     [self](const std::string &contactUri) {
                         auto convIt = getConversationFromUid(convUid_, *accountInfo_->conversationModel.get());
                         if (convIt == accountInfo_->conversationModel->allFilteredConversations().end()) {
                             return;
                         }
                         if (convIt->participants.empty()) {
                             return;

                         }
                         auto& contact = accountInfo_->contactModel->getContact(convIt->participants[0]);
                         if (contact.profileInfo.type == lrc::api::profile::Type::RING && contact.profileInfo.uri == contactUri)
                             accountInfo_->conversationModel->makePermanent(convUid_);
                         [incomingPersonPhoto setImage: [self getContactImageOfSize:120.0 withDefaultAvatar:YES]];
                         [outgoingPhoto setImage: [self getContactImageOfSize:120.0 withDefaultAvatar:YES]];
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
743
                         [self.delegate conversationInfoUpdatedFor:convUid_];
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
744 745 746 747 748 749 750
                         if(accountInfo_->callModel.get()->getCall(callUid_).isAudioOnly) {
                         [audioCallPhoto setImage: [self getContactImageOfSize:120.0 withDefaultAvatar:YES]];
                             [self setBackground];
                             return;
                         }
                         [personPhoto setImage: [self getContactImageOfSize:120.0 withDefaultAvatar:YES]];
                     });
751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778
}

-(void) showWithAnimation:(BOOL)animate
{
    if (!animate) {
        [self.view setHidden:NO];
        [self setupCallView];
        return;
    }

    CGRect frame = CGRectOffset(self.view.superview.bounds, -self.view.superview.bounds.size.width, 0);
    [self.view setHidden:NO];

    [CATransaction begin];
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
    [animation setFromValue:[NSValue valueWithPoint:frame.origin]];
    [animation setToValue:[NSValue valueWithPoint:self.view.superview.bounds.origin]];
    [animation setDuration:0.2f];
    [animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]];
    [CATransaction setCompletionBlock:^{
        [self setupCallView];
    }];

    [self.view.layer addAnimation:animation forKey:animation.keyPath];
    [CATransaction commit];
}

-(void) hideWithAnimation:(BOOL)animate
779 780 781 782 783
{
    if(self.view.frame.origin.x < 0) {
        return;
    }

784 785 786 787 788
    if (!animate) {
        [self.view setHidden:YES];
        return;
    }

789 790 791 792 793 794
    CGRect frame = CGRectOffset(self.view.frame, -self.view.frame.size.width, 0);
    [CATransaction begin];
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
    [animation setFromValue:[NSValue valueWithPoint:self.view.frame.origin]];
    [animation setToValue:[NSValue valueWithPoint:frame.origin]];
    [animation setDuration:0.2f];
795
    [animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]];
796 797 798

    [CATransaction setCompletionBlock:^{
        [self.view setHidden:YES];
799
        // first make sure everything is disconnected
800
        [self cleanUp];
801 802 803
//        if (currentCall_) {
//            [self animateIn];
//        }
804 805
    }];
    [self.view.layer addAnimation:animation forKey:animation.keyPath];
806 807

    [self.view.layer setPosition:frame.origin];
808 809 810 811 812 813 814 815 816 817 818
    [CATransaction commit];
}

/**
 *  Debug purpose
 */
-(void) dumpFrame:(CGRect) frame WithName:(NSString*) name
{
    NSLog(@"frame %@ : %f %f %f %f \n\n",name ,frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
}

819
#pragma mark - Button methods
Alexandre Lision's avatar
Alexandre Lision committed
820

821 822 823
- (IBAction)hangUp:(id)sender {
    if (accountInfo_ == nil)
        return;
Alexandre Lision's avatar
Alexandre Lision committed
824

825
    auto* callModel = accountInfo_->callModel.get();
Alexandre Lision's avatar
Alexandre Lision committed
826

827
    callModel->hangUp(callUid_);
Alexandre Lision's avatar
Alexandre Lision committed
828 829
}

830 831 832
- (IBAction)accept:(id)sender {
    if (accountInfo_ == nil)
        return;
Alexandre Lision's avatar
Alexandre Lision committed
833

834 835 836 837 838 839 840 841
    // If we accept a conversation with a non trusted contact, we first accept it
    auto convIt = getConversationFromUid(convUid_, *accountInfo_->conversationModel.get());
    if (convIt != accountInfo_->conversationModel->allFilteredConversations().end()) {
        auto& contact = accountInfo_->contactModel->getContact(convIt->participants[0]);
        if (contact.profileInfo.type == lrc::api::profile::Type::PENDING)
            accountInfo_->conversationModel->makePermanent(convUid_);
    }

842
    auto* callModel = accountInfo_->callModel.get();
Alexandre Lision's avatar
Alexandre Lision committed
843

844
    callModel->accept(callUid_);
845 846
}

847 848 849
- (IBAction)toggleRecording:(id)sender {
    if (accountInfo_ == nil)
        return;
850

851
    auto* callModel = accountInfo_->callModel.get();
852

853
    callModel->toggleAudioRecord(callUid_);
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
854
    [recordOnOffButton setPressed:!recordOnOffButton.isPressed];
855 856 857
}

- (IBAction)toggleHold:(id)sender {
858 859 860 861
    if (accountInfo_ == nil)
        return;

    auto* callModel = accountInfo_->callModel.get();
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
862 863 864 865 866 867
    auto currentCall = callModel->getCall(callUid_);
    if (currentCall.status != lrc::api::call::Status::PAUSED) {
        holdOnOffButton.image = [NSImage imageNamed:@"ic_action_holdoff.png"];
    } else {
        holdOnOffButton.image = [NSImage imageNamed:@"ic_action_hold.png"];
    }
868 869

    callModel->togglePause(callUid_);
870 871
}

Alexandre Lision's avatar
Alexandre Lision committed
872 873 874 875 876 877 878 879 880 881
- (IBAction)toggleAdvancedControls:(id)sender {
    [advancedButton setPressed:!advancedButton.isPressed];
    [advancedPanel setHidden:![advancedButton isPressed]];
}

- (IBAction)showDialpad:(id)sender {
    AppDelegate* appDelegate = (AppDelegate *)[[NSApplication sharedApplication] delegate];
    [appDelegate showDialpad];
}

Alexandre Lision's avatar
Alexandre Lision committed
882 883 884 885 886 887 888 889
-(IBAction)toggleChat:(id)sender;
{
    BOOL rightViewCollapsed = [[self splitView] isSubviewCollapsed:[[[self splitView] subviews] objectAtIndex: 1]];
    if (rightViewCollapsed) {
        [self uncollapseRightView];
    } else {
        [self collapseRightView];
    }
Alexandre Lision's avatar
Alexandre Lision committed
890
    [chatButton setPressed:rightViewCollapsed];
Alexandre Lision's avatar
Alexandre Lision committed
891 892
}

893 894
- (IBAction)muteAudio:(id)sender
{
895 896 897 898
    if (accountInfo_ == nil)
        return;

    auto* callModel = accountInfo_->callModel.get();
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
899 900 901 902 903 904
    auto currentCall = callModel->getCall(callUid_);
    if (currentCall.audioMuted) {
        muteAudioButton.image = [NSImage imageNamed:@"ic_action_audio.png"];
    } else {
       muteAudioButton.image = [NSImage imageNamed:@"ic_action_mute_audio.png"];
    }
905
    callModel->toggleMedia(callUid_, lrc::api::NewCallModel::Media::AUDIO);
906 907 908 909
}

- (IBAction)muteVideo:(id)sender
{
910 911 912
    if (accountInfo_ == nil)
        return;
    auto* callModel = accountInfo_->callModel.get();
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
913 914 915 916 917 918 919 920
    auto currentCall = callModel->getCall(callUid_);
    if(!currentCall.isAudioOnly) {
        if (currentCall.videoMuted) {
            muteVideoButton.image = [NSImage imageNamed:@"ic_action_video.png"];
        } else {
            muteVideoButton.image = [NSImage imageNamed:@"ic_action_mute_video.png"];
        }
    }
921
    callModel->toggleMedia(callUid_, lrc::api::NewCallModel::Media::VIDEO);
922
}
Alexandre Lision's avatar
Alexandre Lision committed
923 924

- (IBAction)toggleTransferView:(id)sender {
925 926 927
    if (_brokerPopoverVC != nullptr) {
        [_brokerPopoverVC performClose:self];
        _brokerPopoverVC = NULL;
Alexandre Lision's avatar
Alexandre Lision committed
928
        [self.transferButton setPressed:NO];
Alexandre Lision's avatar
Alexandre Lision committed
929
    } else {
930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945
        auto* brokerVC = [[BrokerVC alloc] initWithMode:BrokerMode::TRANSFER];
        _brokerPopoverVC = [[NSPopover alloc] init];
        [_brokerPopoverVC setContentSize:brokerVC.view.frame.size];
        [_brokerPopoverVC setContentViewController:brokerVC];
        [_brokerPopoverVC setAnimates:YES];
        [_brokerPopoverVC setBehavior:NSPopoverBehaviorTransient];
        [_brokerPopoverVC setDelegate:self];
        [_brokerPopoverVC showRelativeToRect:[sender bounds] ofView:sender preferredEdge:NSMinYEdge];
        [videoView setCallDelegate:nil];
    }
}

- (IBAction)toggleAddParticipantView:(id)sender {
    if (_brokerPopoverVC != nullptr) {
        [_brokerPopoverVC performClose:self];
        _brokerPopoverVC = NULL;
Alexandre Lision's avatar
Alexandre Lision committed
946
        [self.addParticipantButton setPressed:NO];
947 948 949 950 951 952 953 954 955
    } else {
        auto* brokerVC = [[BrokerVC alloc] initWithMode:BrokerMode::CONFERENCE];
        _brokerPopoverVC = [[NSPopover alloc] init];
        [_brokerPopoverVC setContentSize:brokerVC.view.frame.size];
        [_brokerPopoverVC setContentViewController:brokerVC];
        [_brokerPopoverVC setAnimates:YES];
        [_brokerPopoverVC setBehavior:NSPopoverBehaviorTransient];
        [_brokerPopoverVC setDelegate:self];
        [_brokerPopoverVC showRelativeToRect:[sender bounds] ofView:sender preferredEdge:NSMinYEdge];
Alexandre Lision's avatar
Alexandre Lision committed
956 957
        [videoView setCallDelegate:nil];
    }
958
}
959

960 961
#pragma mark - NSPopOverDelegate

Alexandre Lision's avatar
Alexandre Lision committed
962 963
- (void)popoverWillClose:(NSNotification *)notification
{
964 965 966
    if (_brokerPopoverVC != nullptr) {
        [_brokerPopoverVC performClose:self];
        _brokerPopoverVC = NULL;
Alexandre Lision's avatar
Alexandre Lision committed
967 968 969 970 971 972 973
    }

    if (self.addToContactPopover != nullptr) {
        [self.addToContactPopover performClose:self];
        self.addToContactPopover = NULL;
    }

Alexandre Lision's avatar
Alexandre Lision committed
974
    [self.transferButton setPressed:NO];
975
    [self.addParticipantButton setState:NSOffState];
Alexandre Lision's avatar
Alexandre Lision committed
976 977
}

978 979
- (void)popoverDidClose:(NSNotification *)notification
{
Alexandre Lision's avatar
Alexandre Lision committed
980
    [videoView setCallDelegate:self];
981 982 983 984 985 986 987 988 989 990 991 992
}

#pragma mark - ContactLinkedDelegate

- (void)contactLinked
{
    if (self.addToContactPopover != nullptr) {
        [self.addToContactPopover performClose:self];
        self.addToContactPopover = NULL;
    }
}

Alexandre Lision's avatar
Alexandre Lision committed
993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010
#pragma mark - NSSplitViewDelegate

/* 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.
 */
- (BOOL)splitView:(NSSplitView *)splitView shouldCollapseSubview:(NSView *)subview forDoubleClickOnDividerAtIndex:(NSInteger)dividerIndex;
{
    NSView* rightView = [[splitView subviews] objectAtIndex:1];
    return ([subview isEqual:rightView]);
}


- (BOOL)splitView:(NSSplitView *)splitView canCollapseSubview:(NSView *)subview;
{
    NSView* rightView = [[splitView subviews] objectAtIndex:1];
    return ([subview isEqual:rightView]);
}


Alexandre Lision's avatar
Alexandre Lision committed
1011
# pragma mark - CallnDelegate
Alexandre Lision's avatar
Alexandre Lision committed
1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026

- (void) callShouldToggleFullScreen
{
    if(self.splitView.isInFullScreenMode)
        [self.splitView exitFullScreenModeWithOptions:nil];
    else {
        NSApplicationPresentationOptions options = NSApplicationPresentationDefault +NSApplicationPresentationAutoHideDock +
        NSApplicationPresentationAutoHideMenuBar + NSApplicationPresentationAutoHideToolbar;
        NSDictionary *opts = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithUnsignedInt:options],
                              NSFullScreenModeApplicationPresentationOptions, nil];

        [self.splitView enterFullScreenMode:[NSScreen mainScreen]  withOptions:opts];
    }
}

Alexandre Lision's avatar
Alexandre Lision committed
1027 1028 1029 1030 1031 1032
-(void) mouseIsMoving:(BOOL) move
{
    [[controlsPanel animato