blob: d2dd465e5adef86f0c79f4c9bf64313b33730a43 [file] [log] [blame]
Alexandre Lisionc5148052015-03-04 15:10:35 -05001/*
Alexandre Lision9fe374b2016-01-06 10:17:31 -05002 * Copyright (C) 2015-2016 Savoir-faire Linux Inc.
Alexandre Lisionc5148052015-03-04 15:10:35 -05003 * Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Alexandre Lisionc5148052015-03-04 15:10:35 -050018 */
19#import "CurrentCallVC.h"
20
21#import <QuartzCore/QuartzCore.h>
22
Alexandre Lision210fe212016-01-27 11:15:13 -050023///Qt
24#import <QMimeData>
25#import <QtMacExtras/qmacfunctions.h>
26#import <QtCore/qabstractitemmodel.h>
27#import <QItemSelectionModel>
28#import <QItemSelection>
29#import <QPixmap>
30
31///LRC
Alexandre Lisionc5148052015-03-04 15:10:35 -050032#import <video/previewmanager.h>
33#import <video/renderer.h>
Olivier Soldano994971f2017-12-05 16:30:12 -050034#import <api/newcallmodel.h>
35#import <api/call.h>
36#import <api/conversationmodel.h>
Alexandre Lision210fe212016-01-27 11:15:13 -050037#import <globalinstances.h>
Alexandre Lisionc5148052015-03-04 15:10:35 -050038
Alexandre Lision62005312016-01-28 15:55:16 -050039#import "AppDelegate.h"
Alexandre Lisionf47a2562015-06-15 15:48:29 -040040#import "views/ITProgressIndicator.h"
Alexandre Lision74dd47f2015-04-14 13:47:42 -040041#import "views/CallView.h"
Kateryna Kostiuk81afce72018-10-30 16:40:50 -040042#import "views/NSColor+RingTheme.h"
Alexandre Lision210fe212016-01-27 11:15:13 -050043#import "delegates/ImageManipulationDelegate.h"
Alexandre Lision2db8f472015-07-22 15:05:46 -040044#import "PersonLinkerVC.h"
Alexandre Lision16d9c0a2015-08-10 12:05:15 -040045#import "ChatVC.h"
Alexandre Lision883719f2015-10-22 17:37:45 -040046#import "BrokerVC.h"
Alexandre Lision4baba4c2016-02-11 13:00:57 -050047#import "views/IconButton.h"
Anthony Léonard14e7bf32017-06-08 08:13:16 -040048#import "views/CallLayer.h"
Anthony Léonard6f819752018-01-05 09:53:40 -050049#import "utils.h"
Alexandre Lision74dd47f2015-04-14 13:47:42 -040050
Alexandre Lisionc5148052015-03-04 15:10:35 -050051@interface RendererConnectionsHolder : NSObject
52
53@property QMetaObject::Connection frameUpdated;
54@property QMetaObject::Connection started;
55@property QMetaObject::Connection stopped;
56
57@end
58
59@implementation RendererConnectionsHolder
60
61@end
62
Olivier Soldano994971f2017-12-05 16:30:12 -050063@interface CurrentCallVC () <NSPopoverDelegate, ContactLinkedDelegate> {
64 std::string convUid_;
65 std::string callUid_;
66 const lrc::api::account::Info *accountInfo_;
Anthony Léonard66a050c2018-01-03 16:32:34 -050067 NSTimer* refreshDurationTimer;
Olivier Soldano994971f2017-12-05 16:30:12 -050068}
Alexandre Lisionc5148052015-03-04 15:10:35 -050069
Alexandre Lision210fe212016-01-27 11:15:13 -050070// Main container
71@property (unsafe_unretained) IBOutlet NSSplitView* splitView;
Kateryna Kostiuk81afce72018-10-30 16:40:50 -040072@property (unsafe_unretained) IBOutlet NSImageView* backgroundImage;
73@property (unsafe_unretained) IBOutlet NSBox* bluerBackgroundEffect;
Alexandre Lision210fe212016-01-27 11:15:13 -050074
Alexandre Lision89edc6a2015-11-09 11:30:47 -050075// Header info
76@property (unsafe_unretained) IBOutlet NSView* headerContainer;
Alexandre Lision883719f2015-10-22 17:37:45 -040077@property (unsafe_unretained) IBOutlet NSTextField* personLabel;
78@property (unsafe_unretained) IBOutlet NSTextField* stateLabel;
Alexandre Lision89edc6a2015-11-09 11:30:47 -050079@property (unsafe_unretained) IBOutlet NSTextField* timeSpentLabel;
Alexandre Lision210fe212016-01-27 11:15:13 -050080@property (unsafe_unretained) IBOutlet NSImageView* personPhoto;
Alexandre Lision89edc6a2015-11-09 11:30:47 -050081
Andreas Traczyk77a50d52018-05-08 17:47:31 -040082@property (unsafe_unretained) IBOutlet NSImageView* outgoingPhoto;
83@property (unsafe_unretained) IBOutlet NSTextField* outgoingPersonLabel;
84@property (unsafe_unretained) IBOutlet NSTextField* outgoingStateLabel;
85@property (unsafe_unretained) IBOutlet NSTextField* outgoingId;
86
Alexandre Lision89edc6a2015-11-09 11:30:47 -050087// Call Controls
88@property (unsafe_unretained) IBOutlet NSView* controlsPanel;
Alexandre Lision62005312016-01-28 15:55:16 -050089
Alexandre Lision4baba4c2016-02-11 13:00:57 -050090@property (unsafe_unretained) IBOutlet IconButton* holdOnOffButton;
91@property (unsafe_unretained) IBOutlet IconButton* hangUpButton;
92@property (unsafe_unretained) IBOutlet IconButton* recordOnOffButton;
93@property (unsafe_unretained) IBOutlet IconButton* pickUpButton;
94@property (unsafe_unretained) IBOutlet IconButton* muteAudioButton;
95@property (unsafe_unretained) IBOutlet IconButton* muteVideoButton;
Alexandre Lision4baba4c2016-02-11 13:00:57 -050096@property (unsafe_unretained) IBOutlet IconButton* transferButton;
97@property (unsafe_unretained) IBOutlet IconButton* addParticipantButton;
98@property (unsafe_unretained) IBOutlet IconButton* chatButton;
Andreas Traczyk77a50d52018-05-08 17:47:31 -040099@property (unsafe_unretained) IBOutlet IconButton* qualityButton;
Alexandre Lisiond18fa272015-06-15 11:18:03 -0400100
Alexandre Lision62005312016-01-28 15:55:16 -0500101@property (unsafe_unretained) IBOutlet NSView* advancedPanel;
102@property (unsafe_unretained) IBOutlet IconButton* advancedButton;
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400103@property (assign) IBOutlet NSLayoutConstraint* callRecordButtonMarginLeft;
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500104
Alexandre Lision2db8f472015-07-22 15:05:46 -0400105@property (strong) NSPopover* addToContactPopover;
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500106@property (strong) NSPopover* brokerPopoverVC;
Alexandre Lision883719f2015-10-22 17:37:45 -0400107@property (strong) IBOutlet ChatVC* chatVC;
Alexandre Lisionf23ec5a2015-07-16 11:24:06 -0400108
Alexandre Lision210fe212016-01-27 11:15:13 -0500109// Ringing call panel
110@property (unsafe_unretained) IBOutlet NSView* ringingPanel;
111@property (unsafe_unretained) IBOutlet NSImageView* incomingPersonPhoto;
112@property (unsafe_unretained) IBOutlet NSTextField* incomingDisplayName;
113
114// Outgoing call panel
115@property (unsafe_unretained) IBOutlet NSView* outgoingPanel;
116@property (unsafe_unretained) IBOutlet ITProgressIndicator *loadingIndicator;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500117
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400118// audio only view
119@property (unsafe_unretained) IBOutlet NSView* audioCallView;
120@property (unsafe_unretained) IBOutlet NSImageView* audioCallPhoto;
121@property (unsafe_unretained) IBOutlet NSTextField* audioCallTime;
122@property (unsafe_unretained) IBOutlet NSTextField* audioCallPersonLabel;
123@property (unsafe_unretained) IBOutlet NSTextField* audioCallPersonId;
124
Alexandre Lisionc5148052015-03-04 15:10:35 -0500125// Video
Alexandre Lision58cab672015-06-09 15:25:40 -0400126@property (unsafe_unretained) IBOutlet CallView *videoView;
Alexandre Lision58cab672015-06-09 15:25:40 -0400127@property (unsafe_unretained) IBOutlet NSView *previewView;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500128
129@property RendererConnectionsHolder* previewHolder;
130@property RendererConnectionsHolder* videoHolder;
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400131@property QMetaObject::Connection videoStarted;
Alexandre Lision4d9905e2016-01-22 12:01:36 -0500132@property QMetaObject::Connection selectedCallChanged;
Alexandre Lisionb65c0272015-07-22 15:51:29 -0400133@property QMetaObject::Connection messageConnection;
134@property QMetaObject::Connection mediaAddedConnection;
Kateryna Kostiuk133364b2018-10-31 11:36:08 -0400135@property QMetaObject::Connection profileUpdatedConnection;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500136
137@end
138
139@implementation CurrentCallVC
Olivier Soldano994971f2017-12-05 16:30:12 -0500140@synthesize personLabel, personPhoto, stateLabel, holdOnOffButton, hangUpButton,
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500141 recordOnOffButton, pickUpButton, chatButton, transferButton, addParticipantButton, timeSpentLabel,
Olivier Soldano994971f2017-12-05 16:30:12 -0500142 muteVideoButton, muteAudioButton, controlsPanel, advancedPanel, advancedButton, headerContainer, videoView,
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400143 incomingDisplayName, incomingPersonPhoto, previewView, splitView, loadingIndicator, ringingPanel,
144 outgoingPanel, outgoingPersonLabel, outgoingStateLabel, outgoingPhoto, outgoingId,
145 callRecordButtonMarginLeft, audioCallView, audioCallPhoto, audioCallTime, audioCallPersonLabel, audioCallPersonId, backgroundImage, bluerBackgroundEffect;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500146
147@synthesize previewHolder;
148@synthesize videoHolder;
149
Olivier Soldano994971f2017-12-05 16:30:12 -0500150-(void) setCurrentCall:(const std::string&)callUid
151 conversation:(const std::string&)convUid
152 account:(const lrc::api::account::Info*)account;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500153{
Olivier Soldano994971f2017-12-05 16:30:12 -0500154 if(account == nil)
155 return;
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400156
Olivier Soldano994971f2017-12-05 16:30:12 -0500157 auto* callModel = account->callModel.get();
Alexandre Lisionc5148052015-03-04 15:10:35 -0500158
Olivier Soldano994971f2017-12-05 16:30:12 -0500159 if (not callModel->hasCall(callUid)){
160 callUid_.clear();
Alexandre Lision2db8f472015-07-22 15:05:46 -0400161 return;
162 }
Olivier Soldano994971f2017-12-05 16:30:12 -0500163 callUid_ = callUid;
164 convUid_ = convUid;
165 accountInfo_ = account;
Anthony Léonard4b0935f2017-12-26 12:05:22 -0500166 [self.chatVC setConversationUid:convUid model:account->conversationModel.get()];
Kateryna Kostiuk54d76972018-06-07 15:45:07 -0400167 auto currentCall = callModel->getCall(callUid_);
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400168 [muteVideoButton setHidden: currentCall.isAudioOnly ? YES: NO];
169 callRecordButtonMarginLeft.constant = currentCall.isAudioOnly ? -40.0f: 10.0f;
170 [previewView setHidden: YES];
Kateryna Kostiukd76f6202018-09-11 17:15:28 -0400171 videoView.callId = callUid;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500172}
173
174- (void)awakeFromNib
175{
176 NSLog(@"INIT CurrentCall VC");
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400177 [self.view setWantsLayer:YES];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500178
Alexandre Lisionc5148052015-03-04 15:10:35 -0500179 [previewView setWantsLayer:YES];
Alexandre Lision22d615b2016-01-25 12:54:34 -0500180 [previewView.layer setBackgroundColor:[NSColor blackColor].CGColor];
181 [previewView.layer setContentsGravity:kCAGravityResizeAspectFill];
182 [previewView.layer setFrame:previewView.frame];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500183
184 [controlsPanel setWantsLayer:YES];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500185 [controlsPanel.layer setBackgroundColor:[NSColor clearColor].CGColor];
186 [controlsPanel.layer setFrame:controlsPanel.frame];
187
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400188 previewHolder = [[RendererConnectionsHolder alloc] init];
189 videoHolder = [[RendererConnectionsHolder alloc] init];
190
Alexandre Lisionf47a2562015-06-15 15:48:29 -0400191 [loadingIndicator setColor:[NSColor whiteColor]];
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400192 [loadingIndicator setNumberOfLines:200];
193 [loadingIndicator setWidthOfLine:4];
194 [loadingIndicator setLengthOfLine:4];
195 [loadingIndicator setInnerMargin:59];
Alexandre Lisionf47a2562015-06-15 15:48:29 -0400196
Alexandre Lisiona1eee3c2015-08-10 13:44:51 -0400197 [self.videoView setCallDelegate:self];
Kateryna Kostiuk1004caa2018-03-29 13:48:07 -0400198 CGColor* color = [[[NSColor blackColor] colorWithAlphaComponent:0.2] CGColor];
199 [headerContainer.layer setBackgroundColor:color];
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400200 [bluerBackgroundEffect setWantsLayer:YES];
201 bluerBackgroundEffect.alphaValue = 0.6;
202 [audioCallView setWantsLayer:YES];
203 [audioCallView.layer setBackgroundColor: [[NSColor clearColor] CGColor]];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500204}
205
Anthony Léonard66a050c2018-01-03 16:32:34 -0500206-(void) updateDurationLabel
207{
208 if (accountInfo_ != nil) {
209 auto* callModel = accountInfo_->callModel.get();
210 if (callModel->hasCall(callUid_)) {
211 auto& callStatus = callModel->getCall(callUid_).status;
212 if (callStatus != lrc::api::call::Status::ENDED &&
213 callStatus != lrc::api::call::Status::TERMINATING &&
214 callStatus != lrc::api::call::Status::INVALID) {
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400215 if(callModel->getCall(callUid_).isAudioOnly) {
216 [audioCallTime setStringValue:@(callModel->getFormattedCallDuration(callUid_).c_str())];
217 } else {
218 [timeSpentLabel setStringValue:@(callModel->getFormattedCallDuration(callUid_).c_str())];
219 }
Anthony Léonard66a050c2018-01-03 16:32:34 -0500220 return;
221 }
222 }
223 }
224
225 // If call is not running anymore or accountInfo_ is not set for any reason
226 // we stop the refresh loop
227 [refreshDurationTimer invalidate];
228 refreshDurationTimer = nil;
229 [timeSpentLabel setHidden:YES];
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400230 [audioCallView setHidden:YES];
Anthony Léonard66a050c2018-01-03 16:32:34 -0500231}
232
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400233-(void) updateCall
Alexandre Lisionc5148052015-03-04 15:10:35 -0500234{
Olivier Soldano994971f2017-12-05 16:30:12 -0500235 if (accountInfo_ == nil)
236 return;
Alexandre Lisionbb5dbcd2015-07-09 16:36:47 -0400237
Olivier Soldano994971f2017-12-05 16:30:12 -0500238 auto* callModel = accountInfo_->callModel.get();
239 if (not callModel->hasCall(callUid_)) {
240 return;
241 }
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500242
Olivier Soldano994971f2017-12-05 16:30:12 -0500243 auto currentCall = callModel->getCall(callUid_);
244 NSLog(@"\n status %@ \n",@(lrc::api::call::to_string(currentCall.status).c_str()));
Anthony Léonard8ee26782018-01-05 10:23:04 -0500245 auto convIt = getConversationFromUid(convUid_, *accountInfo_->conversationModel);
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400246 if (convIt != accountInfo_->conversationModel->allFilteredConversations().end()) {
247 NSString* bestName = bestNameForConversation(*convIt, *accountInfo_->conversationModel);
248 [personLabel setStringValue:bestName];
249 [outgoingPersonLabel setStringValue:bestName];
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400250 [audioCallPersonLabel setStringValue:bestName];
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400251 NSString* ringID = bestIDForConversation(*convIt, *accountInfo_->conversationModel);
252 if([bestName isEqualToString:ringID]) {
253 ringID = @"";
254 }
255 [outgoingId setStringValue:ringID];
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400256 [audioCallPersonId setStringValue:ringID];
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400257 }
258
Anthony Léonard66a050c2018-01-03 16:32:34 -0500259 [timeSpentLabel setStringValue:@(callModel->getFormattedCallDuration(callUid_).c_str())];
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400260 [audioCallTime setStringValue:@(callModel->getFormattedCallDuration(callUid_).c_str())];
Anthony Léonard66a050c2018-01-03 16:32:34 -0500261 if (refreshDurationTimer == nil)
262 refreshDurationTimer = [NSTimer scheduledTimerWithTimeInterval:1.0
263 target:self
264 selector:@selector(updateDurationLabel)
265 userInfo:nil
266 repeats:YES];
Olivier Soldano994971f2017-12-05 16:30:12 -0500267 [stateLabel setStringValue:@(to_string(currentCall.status).c_str())];
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400268 [outgoingStateLabel setStringValue:@(to_string(currentCall.status).c_str())];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500269
Olivier Soldano994971f2017-12-05 16:30:12 -0500270 // Default values for this views
271 [loadingIndicator setHidden:YES];
Olivier Soldano994971f2017-12-05 16:30:12 -0500272 [ringingPanel setHidden:YES];
273 [outgoingPanel setHidden:YES];
274 [controlsPanel setHidden:NO];
275 [headerContainer setHidden:NO];
Anthony Léonard4b0935f2017-12-26 12:05:22 -0500276 [chatButton setHidden:NO];
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400277 [self setBackground];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500278
Olivier Soldano994971f2017-12-05 16:30:12 -0500279 using Status = lrc::api::call::Status;
280 switch (currentCall.status) {
281 case Status::SEARCHING:
Olivier Soldano994971f2017-12-05 16:30:12 -0500282 case Status::CONNECTING:
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400283 [headerContainer setHidden:YES];
284 [outgoingPanel setHidden:NO];
285 [outgoingPhoto setHidden:NO];
286 [self setupContactInfo:outgoingPhoto];
Olivier Soldano994971f2017-12-05 16:30:12 -0500287 [loadingIndicator setHidden:NO];
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400288 [controlsPanel setHidden:YES];
Olivier Soldano994971f2017-12-05 16:30:12 -0500289 break;
290 case Status::INCOMING_RINGING:
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400291 [outgoingPhoto setHidden:YES];
Olivier Soldano994971f2017-12-05 16:30:12 -0500292 [controlsPanel setHidden:YES];
293 [outgoingPanel setHidden:YES];
294 [self setupIncoming:callUid_];
295 break;
296 case Status::OUTGOING_RINGING:
297 [controlsPanel setHidden:YES];
298 [outgoingPanel setHidden:NO];
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400299 [loadingIndicator setHidden:NO];
300 [headerContainer setHidden:YES];
Olivier Soldano994971f2017-12-05 16:30:12 -0500301 break;
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400302 /*case Status::CONFERENCE:
303 [self setupConference:currentCall];
304 break;*/
Olivier Soldano994971f2017-12-05 16:30:12 -0500305 case Status::PAUSED:
Olivier Soldano994971f2017-12-05 16:30:12 -0500306 case Status::INACTIVE:
307 case Status::IN_PROGRESS:
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400308 // change constraints (uncollapse avatar)
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400309 if(currentCall.isAudioOnly) {
310 [self setUpAudioOnlyView];
311 } else {
312 [self setUpVideoCallView];
313 }
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400314 break;
Olivier Soldano994971f2017-12-05 16:30:12 -0500315 case Status::CONNECTED:
Olivier Soldano994971f2017-12-05 16:30:12 -0500316 break;
317 case Status::ENDED:
318 case Status::TERMINATING:
319 case Status::INVALID:
320 [controlsPanel setHidden:YES];
321 [outgoingPanel setHidden:NO];
Andreas Traczykecdc4fa2018-03-22 16:11:47 -0400322 [self hideWithAnimation:false];
Olivier Soldano994971f2017-12-05 16:30:12 -0500323 break;
324 }
Alexandre Lision4d9905e2016-01-22 12:01:36 -0500325
Alexandre Lision4d9905e2016-01-22 12:01:36 -0500326}
327
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400328-(void) setUpVideoCallView {
329 [self setupContactInfo:personPhoto];
330 [timeSpentLabel setHidden:NO];
331 [outgoingPhoto setHidden:YES];
332 [headerContainer setHidden:NO];
333 [previewView setHidden: NO];
334 [bluerBackgroundEffect setHidden:YES];
335 [bluerBackgroundEffect.layer setBackgroundFilters: nil];
336 [backgroundImage setHidden:YES];
337}
338
339-(void) setUpAudioOnlyView {
340 [audioCallView setHidden:NO];
341 [headerContainer setHidden:YES];
342 [audioCallPhoto setImage: [self getContactImageOfSize:120.0 withDefaultAvatar:YES]];
343}
344
345-(void) setBackground {
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400346 auto* convModel = accountInfo_->conversationModel.get();
347 auto it = getConversationFromUid(convUid_, *convModel);
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400348 NSImage *image= [self getContactImageOfSize:120.0 withDefaultAvatar:NO];
349 if(image) {
350 CIFilter* bluerFilter = [CIFilter filterWithName:@"CIGaussianBlur"];
351 [bluerFilter setDefaults];
352 [bluerFilter setValue:[NSNumber numberWithFloat: 30] forKey:@"inputRadius"];
353 [bluerBackgroundEffect.layer setBackgroundFilters:@[bluerFilter]];
354 [backgroundImage setImage: image];
355 [backgroundImage setHidden:NO];
356 } else {
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400357 [bluerBackgroundEffect.layer setBackgroundFilters:nil];
358 [bluerBackgroundEffect setFillColor:[NSColor ringDarkGrey]];
359 [backgroundImage setHidden:YES];
360 [backgroundImage setImage:nil];
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400361 }
362}
363
Kateryna Kostiuk133364b2018-10-31 11:36:08 -0400364-(NSImage *) getContactImageOfSize: (double) size withDefaultAvatar:(BOOL) shouldDrawDefault {
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400365 auto* convModel = accountInfo_->conversationModel.get();
366 auto convIt = getConversationFromUid(convUid_, *convModel);
367 if (convIt == convModel->allFilteredConversations().end()) {
368 return nil;
369 }
370 if(shouldDrawDefault) {
371 auto& imgManip = reinterpret_cast<Interfaces::ImageManipulationDelegate&>(GlobalInstances::pixmapManipulator());
372 QVariant photo = imgManip.conversationPhoto(*convIt, *accountInfo_, QSize(size, size), NO);
373 return QtMac::toNSImage(qvariant_cast<QPixmap>(photo));
374 }
375 auto contact = accountInfo_->contactModel->getContact(convIt->participants[0]);
376 NSData *imageData = [[NSData alloc] initWithBase64EncodedString:@(contact.profileInfo.avatar.c_str()) options:NSDataBase64DecodingIgnoreUnknownCharacters];
377 return [[NSImage alloc] initWithData:imageData];
378}
379
380
381-(void) setupContactInfo:(NSImageView*)imageView
382{
383 [imageView setImage: [self getContactImageOfSize:120.0 withDefaultAvatar:YES]];
384}
385
Olivier Soldano994971f2017-12-05 16:30:12 -0500386-(void) setupIncoming:(const std::string&) callId
Alexandre Lision4d9905e2016-01-22 12:01:36 -0500387{
Olivier Soldano994971f2017-12-05 16:30:12 -0500388 if (accountInfo_ == nil)
389 return;
390
391 auto* callModel = accountInfo_->callModel.get();
392 if (not callModel->hasCall(callUid_)) {
393 return;
394 }
395
396 auto call = callModel->getCall(callUid_);
397 auto* convModel = accountInfo_->conversationModel.get();
398
399 [ringingPanel setHidden:NO];
400 [controlsPanel setHidden:YES];
401 [headerContainer setHidden:YES];
Anthony Léonard6f819752018-01-05 09:53:40 -0500402 auto it = getConversationFromUid(convUid_, *convModel);
Olivier Soldano994971f2017-12-05 16:30:12 -0500403 if (it != convModel->allFilteredConversations().end()) {
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400404 [incomingPersonPhoto setImage: [self getContactImageOfSize:120.0 withDefaultAvatar:YES]];
Anthony Léonard8ee26782018-01-05 10:23:04 -0500405 [incomingDisplayName setStringValue:bestNameForConversation(*it, *convModel)];
Olivier Soldano994971f2017-12-05 16:30:12 -0500406 }
407}
408
409
410-(void) setupConference:(Call*) c
411{
412 [videoView setShouldAcceptInteractions:YES];
413 [self.chatButton setHidden:NO];
Olivier Soldano994971f2017-12-05 16:30:12 -0500414 [self.addParticipantButton setHidden:NO];
415 [self.transferButton setHidden:YES];
416}
417
418-(void)collapseRightView
419{
420 NSView *right = [[splitView subviews] objectAtIndex:1];
421 NSView *left = [[splitView subviews] objectAtIndex:0];
422 NSRect leftFrame = [left frame];
423 [right setHidden:YES];
424 [splitView display];
425}
426
427- (void) changeCallSelection:(std::string&)callUid
428{
429 if (accountInfo_ == nil)
430 return;
431
432 auto* callModel = accountInfo_->callModel.get();
433 if (not callModel->hasCall(callUid)) {
434 return;
435 }
436
Alexandre Lision4d9905e2016-01-22 12:01:36 -0500437 QObject::disconnect(self.selectedCallChanged);
Olivier Soldano994971f2017-12-05 16:30:12 -0500438 self.selectedCallChanged = QObject::connect(callModel,
439 &lrc::api::NewCallModel::callStatusChanged,
440 [self](const std::string callId) {
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400441 [self updateCall];
Alexandre Lision4d9905e2016-01-22 12:01:36 -0500442 });
Alexandre Lisionc5148052015-03-04 15:10:35 -0500443}
444
445-(void) connectVideoSignals
446{
Olivier Soldano994971f2017-12-05 16:30:12 -0500447 if (accountInfo_ == nil)
448 return;
449
450 auto* callModel = accountInfo_->callModel.get();
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500451 QObject::disconnect(self.videoStarted);
Olivier Soldano994971f2017-12-05 16:30:12 -0500452 self.videoStarted = QObject::connect(callModel,
453 &lrc::api::NewCallModel::remotePreviewStarted,
454 [self](const std::string& callId, Video::Renderer* renderer) {
455 NSLog(@"Video started!");
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -0400456 [videoView setLayer:[[CallLayer alloc] init]];
Kateryna Kostiuk1004caa2018-03-29 13:48:07 -0400457 [videoView setShouldAcceptInteractions:YES];
458 [self mouseIsMoving: NO];
Olivier Soldano994971f2017-12-05 16:30:12 -0500459 [self connectVideoRenderer:renderer];
460 });
Alexandre Lisionc5148052015-03-04 15:10:35 -0500461
Olivier Soldano994971f2017-12-05 16:30:12 -0500462 if (callModel->hasCall(callUid_)) {
463 if (auto renderer = callModel->getRenderer(callUid_)) {
464 QObject::disconnect(self.videoStarted);
Kateryna Kostiukbcf24e92018-11-20 10:09:06 -0500465 //[videoView setLayer:[[CallLayer alloc] init]];
Olivier Soldano994971f2017-12-05 16:30:12 -0500466 [self connectVideoRenderer: renderer];
467 }
Alexandre Lisionc5148052015-03-04 15:10:35 -0500468 }
Alexandre Lisionc5148052015-03-04 15:10:35 -0500469 [self connectPreviewRenderer];
470
471}
472
473-(void) connectPreviewRenderer
474{
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400475 QObject::disconnect(previewHolder.frameUpdated);
476 QObject::disconnect(previewHolder.stopped);
477 QObject::disconnect(previewHolder.started);
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400478 previewHolder.started = QObject::connect(&Video::PreviewManager::instance(),
Alexandre Lisionc5148052015-03-04 15:10:35 -0500479 &Video::PreviewManager::previewStarted,
480 [=](Video::Renderer* renderer) {
Alexandre Lisionc5148052015-03-04 15:10:35 -0500481 QObject::disconnect(previewHolder.frameUpdated);
482 previewHolder.frameUpdated = QObject::connect(renderer,
483 &Video::Renderer::frameUpdated,
484 [=]() {
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400485 [self renderer:Video::PreviewManager::instance().previewRenderer()
Anthony Léonard14e7bf32017-06-08 08:13:16 -0400486 renderFrameForPreviewView:previewView];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500487 });
488 });
489
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400490 previewHolder.stopped = QObject::connect(&Video::PreviewManager::instance(),
Alexandre Lisionc5148052015-03-04 15:10:35 -0500491 &Video::PreviewManager::previewStopped,
492 [=](Video::Renderer* renderer) {
Alexandre Lisionc5148052015-03-04 15:10:35 -0500493 QObject::disconnect(previewHolder.frameUpdated);
494 [previewView.layer setContents:nil];
495 });
496
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400497 previewHolder.frameUpdated = QObject::connect(Video::PreviewManager::instance().previewRenderer(),
Alexandre Lisionc5148052015-03-04 15:10:35 -0500498 &Video::Renderer::frameUpdated,
499 [=]() {
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400500 [self renderer:Video::PreviewManager::instance().previewRenderer()
Anthony Léonard14e7bf32017-06-08 08:13:16 -0400501 renderFrameForPreviewView:previewView];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500502 });
503}
504
505-(void) connectVideoRenderer: (Video::Renderer*)renderer
506{
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400507 QObject::disconnect(videoHolder.frameUpdated);
508 QObject::disconnect(videoHolder.started);
509 QObject::disconnect(videoHolder.stopped);
Olivier Soldano994971f2017-12-05 16:30:12 -0500510
511 if(renderer == nil)
512 return;
513
Alexandre Lisionc5148052015-03-04 15:10:35 -0500514 videoHolder.frameUpdated = QObject::connect(renderer,
515 &Video::Renderer::frameUpdated,
516 [=]() {
Anthony Léonard14e7bf32017-06-08 08:13:16 -0400517 [self renderer:renderer renderFrameForDistantView:videoView];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500518 });
519
520 videoHolder.started = QObject::connect(renderer,
521 &Video::Renderer::started,
522 [=]() {
Kateryna Kostiukbcf24e92018-11-20 10:09:06 -0500523 if (![videoView.layer isKindOfClass:[CallLayer class]]) {
524 [videoView setLayer:[[CallLayer alloc] init]];
525 }
Kateryna Kostiuk1004caa2018-03-29 13:48:07 -0400526 [self mouseIsMoving: NO];
527 [videoView setShouldAcceptInteractions:YES];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500528 QObject::disconnect(videoHolder.frameUpdated);
529 videoHolder.frameUpdated = QObject::connect(renderer,
530 &Video::Renderer::frameUpdated,
531 [=]() {
Anthony Léonard14e7bf32017-06-08 08:13:16 -0400532 [self renderer:renderer renderFrameForDistantView:videoView];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500533 });
534 });
535
536 videoHolder.stopped = QObject::connect(renderer,
537 &Video::Renderer::stopped,
538 [=]() {
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -0400539 [videoView setLayer:[CALayer layer]];
540 [videoView.layer setBackgroundColor:[[NSColor blackColor] CGColor]];
Kateryna Kostiuk1004caa2018-03-29 13:48:07 -0400541 [self mouseIsMoving: YES];
542 [videoView setShouldAcceptInteractions:NO];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500543 QObject::disconnect(videoHolder.frameUpdated);
Anthony Léonard14e7bf32017-06-08 08:13:16 -0400544 [(CallLayer*)videoView.layer setVideoRunning:NO];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500545 });
546}
547
Anthony Léonard14e7bf32017-06-08 08:13:16 -0400548-(void) renderer: (Video::Renderer*)renderer renderFrameForPreviewView:(NSView*) view
Alexandre Lisionc5148052015-03-04 15:10:35 -0500549{
Alexandre Lisionc5148052015-03-04 15:10:35 -0500550 QSize res = renderer->size();
551
Alexandre Lision6731e132015-10-14 14:29:06 -0400552 auto frame_ptr = renderer->currentFrame();
553 auto frame_data = frame_ptr.ptr;
554 if (!frame_data)
555 return;
556
Alexandre Lisionc5148052015-03-04 15:10:35 -0500557 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
Alexandre Lision6731e132015-10-14 14:29:06 -0400558 CGContextRef newContext = CGBitmapContextCreate(frame_data,
Alexandre Lisionc5148052015-03-04 15:10:35 -0500559 res.width(),
560 res.height(),
561 8,
562 4*res.width(),
563 colorSpace,
564 kCGImageAlphaPremultipliedLast);
565
566
567 CGImageRef newImage = CGBitmapContextCreateImage(newContext);
568
569 /*We release some components*/
570 CGContextRelease(newContext);
571 CGColorSpaceRelease(colorSpace);
572
573 [CATransaction begin];
574 view.layer.contents = (__bridge id)newImage;
575 [CATransaction commit];
576
577 CFRelease(newImage);
578}
579
Anthony Léonard14e7bf32017-06-08 08:13:16 -0400580-(void) renderer: (Video::Renderer*)renderer renderFrameForDistantView:(CallView*) view
581{
Anthony Léonard14e7bf32017-06-08 08:13:16 -0400582 auto frame_ptr = renderer->currentFrame();
583 if (!frame_ptr.ptr)
584 return;
585
586 CallLayer* callLayer = (CallLayer*) view.layer;
Kateryna Kostiukbcf24e92018-11-20 10:09:06 -0500587 if ([callLayer respondsToSelector:@selector(setCurrentFrame:)]) {
588 [callLayer setCurrentFrame:std::move(frame_ptr)];
589 [callLayer setVideoRunning:YES];
590 }
Anthony Léonard14e7bf32017-06-08 08:13:16 -0400591}
592
Alexandre Lisionc5148052015-03-04 15:10:35 -0500593- (void) initFrame
594{
595 [self.view setFrame:self.view.superview.bounds];
596 [self.view setHidden:YES];
597 self.view.layer.position = self.view.frame.origin;
Alexandre Lisionbb5dbcd2015-07-09 16:36:47 -0400598 [self collapseRightView];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500599}
600
601# pragma private IN/OUT animations
602
Olivier Soldano994971f2017-12-05 16:30:12 -0500603-(void)uncollapseRightView
604{
605 NSView *left = [[splitView subviews] objectAtIndex:0];
606 NSView *right = [[splitView subviews] objectAtIndex:1];
607 [right setHidden:NO];
608
609 CGFloat dividerThickness = [splitView dividerThickness];
610
611 // get the different frames
612 NSRect leftFrame = [left frame];
613 NSRect rightFrame = [right frame];
614
615 leftFrame.size.width = (leftFrame.size.width - rightFrame.size.width - dividerThickness);
616 rightFrame.origin.x = leftFrame.size.width + dividerThickness;
617 [left setFrameSize:leftFrame.size];
618 [right setFrame:rightFrame];
619 [splitView display];
620
621 [self.chatVC takeFocus];
622}
623
Alexandre Lisionc5148052015-03-04 15:10:35 -0500624-(void) cleanUp
625{
Anthony Léonard5c287642018-02-21 15:54:19 -0500626 if(self.splitView.isInFullScreenMode)
627 [self.splitView exitFullScreenModeWithOptions:nil];
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400628 QObject::disconnect(videoHolder.frameUpdated);
629 QObject::disconnect(videoHolder.started);
630 QObject::disconnect(videoHolder.stopped);
631 QObject::disconnect(previewHolder.frameUpdated);
632 QObject::disconnect(previewHolder.stopped);
633 QObject::disconnect(previewHolder.started);
Anthony Léonardc0013bb2018-02-20 16:23:02 -0500634 QObject::disconnect(self.messageConnection);
Alexandre Lisionc5148052015-03-04 15:10:35 -0500635 [previewView.layer setContents:nil];
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400636 [previewView setHidden: YES];
Kateryna Kostiukc17db8d2018-10-23 09:48:03 -0400637 [videoView setLayer:[CALayer layer]];
638 [videoView.layer setBackgroundColor:[[NSColor blackColor] CGColor]];
Alexandre Lision883719f2015-10-22 17:37:45 -0400639
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500640 [self.chatButton setHidden:YES];
Alexandre Lision4baba4c2016-02-11 13:00:57 -0500641 [self.chatButton setPressed:NO];
Alexandre Lision883719f2015-10-22 17:37:45 -0400642 [self collapseRightView];
Alexandre Lision57227772016-01-15 17:19:36 -0500643
644 [personLabel setStringValue:@""];
645 [timeSpentLabel setStringValue:@""];
646 [stateLabel setStringValue:@""];
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400647 //audio view
648 [audioCallTime setStringValue:@""];
649 [audioCallPersonId setStringValue:@""];
650 [audioCallPersonLabel setStringValue:@""];
651 [audioCallView setHidden:YES];
652 [audioCallPhoto setImage:nil];
653 //background view
654 [bluerBackgroundEffect setHidden:NO];
655 [backgroundImage setHidden:NO];
656 [backgroundImage setImage:nil];
657 [bluerBackgroundEffect setBackgroundFilters:nil];
658 //outgoing view
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400659 [outgoingPersonLabel setStringValue:@""];
660 [outgoingStateLabel setStringValue:@""];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500661}
662
Andreas Traczykecdc4fa2018-03-22 16:11:47 -0400663-(void) setupCallView
664{
665 if (accountInfo_ == nil)
666 return;
667
668 auto* callModel = accountInfo_->callModel.get();
669 auto* convModel = accountInfo_->conversationModel.get();
670
671 // when call comes in we want to show the controls/header
Kateryna Kostiuk1004caa2018-03-29 13:48:07 -0400672 [self mouseIsMoving: YES];
673 [videoView setShouldAcceptInteractions: NO];
Andreas Traczykecdc4fa2018-03-22 16:11:47 -0400674
675 [self connectVideoSignals];
676 /* check if text media is already present */
677 if(not callModel->hasCall(callUid_))
678 return;
679
680 [loadingIndicator setAnimates:YES];
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400681 [self updateCall];
Andreas Traczykecdc4fa2018-03-22 16:11:47 -0400682
683 /* monitor media for messaging text messaging */
684 QObject::disconnect(self.messageConnection);
685 self.messageConnection = QObject::connect(convModel,
686 &lrc::api::ConversationModel::interactionStatusUpdated,
687 [self] (std::string convUid,
688 uint64_t msgId,
689 lrc::api::interaction::Info msg) {
690 if (msg.type == lrc::api::interaction::Type::TEXT) {
691 if(not [[self splitView] isSubviewCollapsed:[[[self splitView] subviews] objectAtIndex: 1]]){
692 return;
693 }
694 [self uncollapseRightView];
695 }
696 });
Kateryna Kostiuk133364b2018-10-31 11:36:08 -0400697 //monitor for updated profile
698 QObject::disconnect(self.profileUpdatedConnection);
699 self.profileUpdatedConnection =
700 QObject::connect(accountInfo_->contactModel.get(),
701 &lrc::api::ContactModel::contactAdded,
702 [self](const std::string &contactUri) {
703 auto convIt = getConversationFromUid(convUid_, *accountInfo_->conversationModel.get());
704 if (convIt == accountInfo_->conversationModel->allFilteredConversations().end()) {
705 return;
706 }
707 if (convIt->participants.empty()) {
708 return;
709
710 }
711 auto& contact = accountInfo_->contactModel->getContact(convIt->participants[0]);
712 if (contact.profileInfo.type == lrc::api::profile::Type::RING && contact.profileInfo.uri == contactUri)
713 accountInfo_->conversationModel->makePermanent(convUid_);
714 [incomingPersonPhoto setImage: [self getContactImageOfSize:120.0 withDefaultAvatar:YES]];
715 [outgoingPhoto setImage: [self getContactImageOfSize:120.0 withDefaultAvatar:YES]];
716 [self.delegate conversationInfoUpdatedFor:convUid_];
717 if(accountInfo_->callModel.get()->getCall(callUid_).isAudioOnly) {
718 [audioCallPhoto setImage: [self getContactImageOfSize:120.0 withDefaultAvatar:YES]];
719 [self setBackground];
720 return;
721 }
722 [personPhoto setImage: [self getContactImageOfSize:120.0 withDefaultAvatar:YES]];
723 });
Andreas Traczykecdc4fa2018-03-22 16:11:47 -0400724}
725
726-(void) showWithAnimation:(BOOL)animate
727{
728 if (!animate) {
729 [self.view setHidden:NO];
730 [self setupCallView];
731 return;
732 }
733
734 CGRect frame = CGRectOffset(self.view.superview.bounds, -self.view.superview.bounds.size.width, 0);
735 [self.view setHidden:NO];
736
737 [CATransaction begin];
738 CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
739 [animation setFromValue:[NSValue valueWithPoint:frame.origin]];
740 [animation setToValue:[NSValue valueWithPoint:self.view.superview.bounds.origin]];
741 [animation setDuration:0.2f];
742 [animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]];
743 [CATransaction setCompletionBlock:^{
744 [self setupCallView];
745 }];
746
747 [self.view.layer addAnimation:animation forKey:animation.keyPath];
748 [CATransaction commit];
749}
750
751-(void) hideWithAnimation:(BOOL)animate
Alexandre Lisionc5148052015-03-04 15:10:35 -0500752{
Alexandre Lisionc5148052015-03-04 15:10:35 -0500753 if(self.view.frame.origin.x < 0) {
Alexandre Lisionc5148052015-03-04 15:10:35 -0500754 return;
755 }
756
Andreas Traczykecdc4fa2018-03-22 16:11:47 -0400757 if (!animate) {
Kateryna Kostiuk1004caa2018-03-29 13:48:07 -0400758 [self cleanUp];
Andreas Traczykecdc4fa2018-03-22 16:11:47 -0400759 [self.view setHidden:YES];
760 return;
761 }
762
Alexandre Lisionc5148052015-03-04 15:10:35 -0500763 CGRect frame = CGRectOffset(self.view.frame, -self.view.frame.size.width, 0);
764 [CATransaction begin];
765 CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
766 [animation setFromValue:[NSValue valueWithPoint:self.view.frame.origin]];
767 [animation setToValue:[NSValue valueWithPoint:frame.origin]];
768 [animation setDuration:0.2f];
Alexandre Lision22d615b2016-01-25 12:54:34 -0500769 [animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500770
771 [CATransaction setCompletionBlock:^{
772 [self.view setHidden:YES];
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400773 // first make sure everything is disconnected
Alexandre Lisionc5148052015-03-04 15:10:35 -0500774 [self cleanUp];
Olivier Soldano994971f2017-12-05 16:30:12 -0500775// if (currentCall_) {
776// [self animateIn];
777// }
Alexandre Lisionc5148052015-03-04 15:10:35 -0500778 }];
779 [self.view.layer addAnimation:animation forKey:animation.keyPath];
Alexandre Lisiona1c6d752015-06-23 12:27:38 -0400780
781 [self.view.layer setPosition:frame.origin];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500782 [CATransaction commit];
783}
784
785/**
786 * Debug purpose
787 */
788-(void) dumpFrame:(CGRect) frame WithName:(NSString*) name
789{
790 NSLog(@"frame %@ : %f %f %f %f \n\n",name ,frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
791}
792
Alexandre Lision58cab672015-06-09 15:25:40 -0400793#pragma mark - Button methods
794
Alexandre Lisionc5148052015-03-04 15:10:35 -0500795- (IBAction)hangUp:(id)sender {
Olivier Soldano994971f2017-12-05 16:30:12 -0500796 if (accountInfo_ == nil)
797 return;
798
799 auto* callModel = accountInfo_->callModel.get();
800
801 callModel->hangUp(callUid_);
Alexandre Lisionc5148052015-03-04 15:10:35 -0500802}
803
804- (IBAction)accept:(id)sender {
Olivier Soldano994971f2017-12-05 16:30:12 -0500805 if (accountInfo_ == nil)
806 return;
807
Anthony Léonardf584cc52018-01-19 12:00:19 -0500808 // If we accept a conversation with a non trusted contact, we first accept it
809 auto convIt = getConversationFromUid(convUid_, *accountInfo_->conversationModel.get());
810 if (convIt != accountInfo_->conversationModel->allFilteredConversations().end()) {
811 auto& contact = accountInfo_->contactModel->getContact(convIt->participants[0]);
812 if (contact.profileInfo.type == lrc::api::profile::Type::PENDING)
813 accountInfo_->conversationModel->makePermanent(convUid_);
814 }
815
Olivier Soldano994971f2017-12-05 16:30:12 -0500816 auto* callModel = accountInfo_->callModel.get();
817
818 callModel->accept(callUid_);
Alexandre Lisionc5148052015-03-04 15:10:35 -0500819}
820
821- (IBAction)toggleRecording:(id)sender {
Olivier Soldano994971f2017-12-05 16:30:12 -0500822 if (accountInfo_ == nil)
823 return;
824
825 auto* callModel = accountInfo_->callModel.get();
826
827 callModel->toggleAudioRecord(callUid_);
Kateryna Kostiuk54d76972018-06-07 15:45:07 -0400828 [recordOnOffButton setPressed:!recordOnOffButton.isPressed];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500829}
830
831- (IBAction)toggleHold:(id)sender {
Olivier Soldano994971f2017-12-05 16:30:12 -0500832 if (accountInfo_ == nil)
833 return;
834
835 auto* callModel = accountInfo_->callModel.get();
Kateryna Kostiuk54d76972018-06-07 15:45:07 -0400836 auto currentCall = callModel->getCall(callUid_);
837 if (currentCall.status != lrc::api::call::Status::PAUSED) {
838 holdOnOffButton.image = [NSImage imageNamed:@"ic_action_holdoff.png"];
839 } else {
840 holdOnOffButton.image = [NSImage imageNamed:@"ic_action_hold.png"];
841 }
Olivier Soldano994971f2017-12-05 16:30:12 -0500842
843 callModel->togglePause(callUid_);
Alexandre Lisionc5148052015-03-04 15:10:35 -0500844}
845
Alexandre Lision62005312016-01-28 15:55:16 -0500846- (IBAction)toggleAdvancedControls:(id)sender {
847 [advancedButton setPressed:!advancedButton.isPressed];
848 [advancedPanel setHidden:![advancedButton isPressed]];
849}
850
851- (IBAction)showDialpad:(id)sender {
852 AppDelegate* appDelegate = (AppDelegate *)[[NSApplication sharedApplication] delegate];
853 [appDelegate showDialpad];
854}
855
Alexandre Lision58cab672015-06-09 15:25:40 -0400856-(IBAction)toggleChat:(id)sender;
857{
858 BOOL rightViewCollapsed = [[self splitView] isSubviewCollapsed:[[[self splitView] subviews] objectAtIndex: 1]];
859 if (rightViewCollapsed) {
860 [self uncollapseRightView];
Alexandre Lision58cab672015-06-09 15:25:40 -0400861 } else {
862 [self collapseRightView];
863 }
Alexandre Lision62005312016-01-28 15:55:16 -0500864 [chatButton setPressed:rightViewCollapsed];
Alexandre Lision58cab672015-06-09 15:25:40 -0400865}
866
Alexandre Lisiond18fa272015-06-15 11:18:03 -0400867- (IBAction)muteAudio:(id)sender
868{
Olivier Soldano994971f2017-12-05 16:30:12 -0500869 if (accountInfo_ == nil)
870 return;
871
872 auto* callModel = accountInfo_->callModel.get();
Kateryna Kostiuk54d76972018-06-07 15:45:07 -0400873 auto currentCall = callModel->getCall(callUid_);
874 if (currentCall.audioMuted) {
875 muteAudioButton.image = [NSImage imageNamed:@"ic_action_audio.png"];
876 } else {
877 muteAudioButton.image = [NSImage imageNamed:@"ic_action_mute_audio.png"];
878 }
Olivier Soldano994971f2017-12-05 16:30:12 -0500879 callModel->toggleMedia(callUid_, lrc::api::NewCallModel::Media::AUDIO);
Alexandre Lisiond18fa272015-06-15 11:18:03 -0400880}
881
882- (IBAction)muteVideo:(id)sender
883{
Olivier Soldano994971f2017-12-05 16:30:12 -0500884 if (accountInfo_ == nil)
885 return;
Olivier Soldano994971f2017-12-05 16:30:12 -0500886 auto* callModel = accountInfo_->callModel.get();
Kateryna Kostiuk54d76972018-06-07 15:45:07 -0400887 auto currentCall = callModel->getCall(callUid_);
888 if(!currentCall.isAudioOnly) {
889 if (currentCall.videoMuted) {
890 muteVideoButton.image = [NSImage imageNamed:@"ic_action_video.png"];
891 } else {
892 muteVideoButton.image = [NSImage imageNamed:@"ic_action_mute_video.png"];
893 }
894 }
Olivier Soldano994971f2017-12-05 16:30:12 -0500895 callModel->toggleMedia(callUid_, lrc::api::NewCallModel::Media::VIDEO);
Alexandre Lisiond18fa272015-06-15 11:18:03 -0400896}
Alexandre Lision883719f2015-10-22 17:37:45 -0400897
898- (IBAction)toggleTransferView:(id)sender {
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500899 if (_brokerPopoverVC != nullptr) {
900 [_brokerPopoverVC performClose:self];
901 _brokerPopoverVC = NULL;
Alexandre Lision62005312016-01-28 15:55:16 -0500902 [self.transferButton setPressed:NO];
Alexandre Lision883719f2015-10-22 17:37:45 -0400903 } else {
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500904 auto* brokerVC = [[BrokerVC alloc] initWithMode:BrokerMode::TRANSFER];
905 _brokerPopoverVC = [[NSPopover alloc] init];
906 [_brokerPopoverVC setContentSize:brokerVC.view.frame.size];
907 [_brokerPopoverVC setContentViewController:brokerVC];
908 [_brokerPopoverVC setAnimates:YES];
909 [_brokerPopoverVC setBehavior:NSPopoverBehaviorTransient];
910 [_brokerPopoverVC setDelegate:self];
911 [_brokerPopoverVC showRelativeToRect:[sender bounds] ofView:sender preferredEdge:NSMinYEdge];
Alexandre Lision883719f2015-10-22 17:37:45 -0400912 [videoView setCallDelegate:nil];
913 }
Alexandre Lisionf23ec5a2015-07-16 11:24:06 -0400914}
Alexandre Lisiond18fa272015-06-15 11:18:03 -0400915
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500916- (IBAction)toggleAddParticipantView:(id)sender {
917 if (_brokerPopoverVC != nullptr) {
918 [_brokerPopoverVC performClose:self];
919 _brokerPopoverVC = NULL;
Alexandre Lision62005312016-01-28 15:55:16 -0500920 [self.addParticipantButton setPressed:NO];
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500921 } else {
922 auto* brokerVC = [[BrokerVC alloc] initWithMode:BrokerMode::CONFERENCE];
923 _brokerPopoverVC = [[NSPopover alloc] init];
924 [_brokerPopoverVC setContentSize:brokerVC.view.frame.size];
925 [_brokerPopoverVC setContentViewController:brokerVC];
926 [_brokerPopoverVC setAnimates:YES];
927 [_brokerPopoverVC setBehavior:NSPopoverBehaviorTransient];
928 [_brokerPopoverVC setDelegate:self];
929 [_brokerPopoverVC showRelativeToRect:[sender bounds] ofView:sender preferredEdge:NSMinYEdge];
930 [videoView setCallDelegate:nil];
931 }
932}
933
Alexandre Lision2db8f472015-07-22 15:05:46 -0400934#pragma mark - NSPopOverDelegate
935
Alexandre Lision266fca02015-09-28 14:47:05 -0400936- (void)popoverWillClose:(NSNotification *)notification
937{
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500938 if (_brokerPopoverVC != nullptr) {
939 [_brokerPopoverVC performClose:self];
940 _brokerPopoverVC = NULL;
Alexandre Lision883719f2015-10-22 17:37:45 -0400941 }
Alexandre Lision266fca02015-09-28 14:47:05 -0400942
Alexandre Lision2db8f472015-07-22 15:05:46 -0400943 if (self.addToContactPopover != nullptr) {
944 [self.addToContactPopover performClose:self];
945 self.addToContactPopover = NULL;
946 }
Alexandre Lision883719f2015-10-22 17:37:45 -0400947
Alexandre Lision62005312016-01-28 15:55:16 -0500948 [self.transferButton setPressed:NO];
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500949 [self.addParticipantButton setState:NSOffState];
Alexandre Lision883719f2015-10-22 17:37:45 -0400950}
951
952- (void)popoverDidClose:(NSNotification *)notification
953{
954 [videoView setCallDelegate:self];
Alexandre Lision2db8f472015-07-22 15:05:46 -0400955}
956
957#pragma mark - ContactLinkedDelegate
958
959- (void)contactLinked
960{
961 if (self.addToContactPopover != nullptr) {
962 [self.addToContactPopover performClose:self];
963 self.addToContactPopover = NULL;
964 }
965}
966
Alexandre Lision58cab672015-06-09 15:25:40 -0400967#pragma mark - NSSplitViewDelegate
968
969/* 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.
970 */
971- (BOOL)splitView:(NSSplitView *)splitView shouldCollapseSubview:(NSView *)subview forDoubleClickOnDividerAtIndex:(NSInteger)dividerIndex;
972{
973 NSView* rightView = [[splitView subviews] objectAtIndex:1];
974 return ([subview isEqual:rightView]);
975}
976
977
978- (BOOL)splitView:(NSSplitView *)splitView canCollapseSubview:(NSView *)subview;
979{
980 NSView* rightView = [[splitView subviews] objectAtIndex:1];
981 return ([subview isEqual:rightView]);
982}
983
984
Alexandre Lisiona1eee3c2015-08-10 13:44:51 -0400985# pragma mark - CallnDelegate
Alexandre Lision58cab672015-06-09 15:25:40 -0400986
987- (void) callShouldToggleFullScreen
988{
989 if(self.splitView.isInFullScreenMode)
990 [self.splitView exitFullScreenModeWithOptions:nil];
991 else {
992 NSApplicationPresentationOptions options = NSApplicationPresentationDefault +NSApplicationPresentationAutoHideDock +
993 NSApplicationPresentationAutoHideMenuBar + NSApplicationPresentationAutoHideToolbar;
994 NSDictionary *opts = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithUnsignedInt:options],
995 NSFullScreenModeApplicationPresentationOptions, nil];
996
997 [self.splitView enterFullScreenMode:[NSScreen mainScreen] withOptions:opts];
998 }
999}
1000
Alexandre Lisiona1eee3c2015-08-10 13:44:51 -04001001-(void) mouseIsMoving:(BOOL) move
1002{
1003 [[controlsPanel animator] setAlphaValue:move]; // fade out
1004 [[headerContainer animator] setAlphaValue:move];
1005}
1006
Alexandre Lisionc5148052015-03-04 15:10:35 -05001007@end