blob: d0022cf0bf188d6a8fd0a1e5bbf68a7a5e5e1749 [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"
Kateryna Kostiuk00dcbff2019-07-11 15:42:13 -040020extern "C" {
21#import "libavutil/frame.h"
22#import "libavutil/display.h"
23}
Alexandre Lisionc5148052015-03-04 15:10:35 -050024
25#import <QuartzCore/QuartzCore.h>
26
Alexandre Lision210fe212016-01-27 11:15:13 -050027///Qt
28#import <QMimeData>
29#import <QtMacExtras/qmacfunctions.h>
30#import <QtCore/qabstractitemmodel.h>
Alexandre Lision210fe212016-01-27 11:15:13 -050031#import <QPixmap>
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -040032#import <QUrl>
Alexandre Lision210fe212016-01-27 11:15:13 -050033
34///LRC
Alexandre Lisionc5148052015-03-04 15:10:35 -050035#import <video/renderer.h>
Olivier Soldano994971f2017-12-05 16:30:12 -050036#import <api/newcallmodel.h>
37#import <api/call.h>
38#import <api/conversationmodel.h>
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -040039#import <api/avmodel.h>
Alexandre Lision210fe212016-01-27 11:15:13 -050040#import <globalinstances.h>
Alexandre Lisionc5148052015-03-04 15:10:35 -050041
Alexandre Lision62005312016-01-28 15:55:16 -050042#import "AppDelegate.h"
Alexandre Lisionf47a2562015-06-15 15:48:29 -040043#import "views/ITProgressIndicator.h"
Alexandre Lision74dd47f2015-04-14 13:47:42 -040044#import "views/CallView.h"
Kateryna Kostiuk81afce72018-10-30 16:40:50 -040045#import "views/NSColor+RingTheme.h"
Alexandre Lision210fe212016-01-27 11:15:13 -050046#import "delegates/ImageManipulationDelegate.h"
Alexandre Lision16d9c0a2015-08-10 12:05:15 -040047#import "ChatVC.h"
Alexandre Lision4baba4c2016-02-11 13:00:57 -050048#import "views/IconButton.h"
Anthony Léonard6f819752018-01-05 09:53:40 -050049#import "utils.h"
Kateryna Kostiuk00dcbff2019-07-11 15:42:13 -040050#import "views/CallMTKView.h"
Kateryna Kostiukc5fd3b92019-07-24 10:12:44 -040051#import "VideoCommon.h"
Kateryna Kostiuk88a6ee82019-09-10 17:55:08 -040052#import "views/GradientView.h"
Kateryna Kostiuk6891d4f2019-09-19 17:44:33 -040053#import "views/MovableView.h"
Kateryna Kostiuk06681682020-05-07 20:50:56 -040054#import "views/RenderingView.h"
Alexandre Lision74dd47f2015-04-14 13:47:42 -040055
Kateryna Kostiuk1ba5a012018-12-12 17:07:38 -050056@interface CurrentCallVC () <NSPopoverDelegate> {
Kateryna Kostiukc867eb92020-03-08 13:15:17 -040057 QString convUid_;
58 QString callUid_;
59 QString confUid_;
Olivier Soldano994971f2017-12-05 16:30:12 -050060 const lrc::api::account::Info *accountInfo_;
Anthony Léonard66a050c2018-01-03 16:32:34 -050061 NSTimer* refreshDurationTimer;
Olivier Soldano994971f2017-12-05 16:30:12 -050062}
Alexandre Lisionc5148052015-03-04 15:10:35 -050063
Alexandre Lision210fe212016-01-27 11:15:13 -050064// Main container
65@property (unsafe_unretained) IBOutlet NSSplitView* splitView;
Kateryna Kostiuk89398b62018-11-20 16:45:04 -050066@property (unsafe_unretained) IBOutlet NSView* backgroundImage;
Kateryna Kostiuk81afce72018-10-30 16:40:50 -040067@property (unsafe_unretained) IBOutlet NSBox* bluerBackgroundEffect;
Alexandre Lision210fe212016-01-27 11:15:13 -050068
Alexandre Lision89edc6a2015-11-09 11:30:47 -050069// Header info
70@property (unsafe_unretained) IBOutlet NSView* headerContainer;
Kateryna Kostiuk2aa39232019-10-10 11:55:11 -040071@property (unsafe_unretained) IBOutlet NSView* headerGradientView;
Alexandre Lision89edc6a2015-11-09 11:30:47 -050072@property (unsafe_unretained) IBOutlet NSTextField* timeSpentLabel;
73
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -040074// info
75@property (unsafe_unretained) IBOutlet NSStackView* infoContainer;
76@property (unsafe_unretained) IBOutlet NSImageView* contactPhoto;
77@property (unsafe_unretained) IBOutlet NSTextField* contactNameLabel;
78@property (unsafe_unretained) IBOutlet NSTextField* callStateLabel;
79@property (unsafe_unretained) IBOutlet NSTextField* contactIdLabel;
80@property (unsafe_unretained) IBOutlet IconButton* cancelCallButton;
81@property (unsafe_unretained) IBOutlet IconButton* pickUpButton;
82@property (unsafe_unretained) IBOutlet ITProgressIndicator *loadingIndicator;
Andreas Traczyk77a50d52018-05-08 17:47:31 -040083
Alexandre Lision89edc6a2015-11-09 11:30:47 -050084// Call Controls
Kateryna Kostiuk88a6ee82019-09-10 17:55:08 -040085@property (unsafe_unretained) IBOutlet GradientView* controlsPanel;
Kateryna Kostiuk2aa39232019-10-10 11:55:11 -040086@property (unsafe_unretained) IBOutlet NSStackView* controlsStackView;
Alexandre Lision62005312016-01-28 15:55:16 -050087
Alexandre Lision4baba4c2016-02-11 13:00:57 -050088@property (unsafe_unretained) IBOutlet IconButton* holdOnOffButton;
89@property (unsafe_unretained) IBOutlet IconButton* hangUpButton;
90@property (unsafe_unretained) IBOutlet IconButton* recordOnOffButton;
Alexandre Lision4baba4c2016-02-11 13:00:57 -050091@property (unsafe_unretained) IBOutlet IconButton* muteAudioButton;
92@property (unsafe_unretained) IBOutlet IconButton* muteVideoButton;
Alexandre Lision4baba4c2016-02-11 13:00:57 -050093@property (unsafe_unretained) IBOutlet IconButton* transferButton;
94@property (unsafe_unretained) IBOutlet IconButton* addParticipantButton;
95@property (unsafe_unretained) IBOutlet IconButton* chatButton;
Andreas Traczyk77a50d52018-05-08 17:47:31 -040096@property (unsafe_unretained) IBOutlet IconButton* qualityButton;
Alexandre Lisiond18fa272015-06-15 11:18:03 -040097
Alexandre Lisionc5148052015-03-04 15:10:35 -050098// Video
Alexandre Lision58cab672015-06-09 15:25:40 -040099@property (unsafe_unretained) IBOutlet CallView *videoView;
Kateryna Kostiuk06681682020-05-07 20:50:56 -0400100@property (unsafe_unretained) IBOutlet RenderingView *previewView;
Kateryna Kostiuk6891d4f2019-09-19 17:44:33 -0400101@property (unsafe_unretained) IBOutlet MovableView *movableBaseForView;
102@property (unsafe_unretained) IBOutlet NSView* hidePreviewBackground;
103@property (unsafe_unretained) IBOutlet NSButton* hidePreviewButton;
Kateryna Kostiuk00dcbff2019-07-11 15:42:13 -0400104
Kateryna Kostiuk06681682020-05-07 20:50:56 -0400105@property (unsafe_unretained) IBOutlet RenderingView *distantView;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500106
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400107@property RendererConnectionsHolder* renderConnections;
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400108@property QMetaObject::Connection videoStarted;
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400109@property QMetaObject::Connection callStateChanged;
Alexandre Lisionb65c0272015-07-22 15:51:29 -0400110@property QMetaObject::Connection messageConnection;
Kateryna Kostiuk133364b2018-10-31 11:36:08 -0400111@property QMetaObject::Connection profileUpdatedConnection;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500112
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400113//conference
114@property (unsafe_unretained) IBOutlet NSStackView *callingWidgetsContainer;
115
116@property (strong) NSPopover* brokerPopoverVC;
117
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400118@property (strong) IBOutlet ChatVC* chatVC;
119
Alexandre Lisionc5148052015-03-04 15:10:35 -0500120@end
121
122@implementation CurrentCallVC
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400123lrc::api::AVModel* mediaModel;
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400124NSMutableDictionary *connectingCalls;
Kateryna Kostiuk6891d4f2019-09-19 17:44:33 -0400125
126NSInteger const PREVIEW_WIDTH = 185;
127NSInteger const PREVIEW_HEIGHT = 130;
Kateryna Kostiuk2aa39232019-10-10 11:55:11 -0400128NSInteger const HIDE_PREVIEW_BUTTON_SIZE = 25;
Kateryna Kostiuk6891d4f2019-09-19 17:44:33 -0400129NSInteger const PREVIEW_MARGIN = 20;
130
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400131@synthesize holdOnOffButton, hangUpButton, recordOnOffButton, pickUpButton, chatButton, transferButton, addParticipantButton, timeSpentLabel, muteVideoButton, muteAudioButton, controlsPanel, headerContainer, videoView, previewView, splitView, loadingIndicator, backgroundImage, bluerBackgroundEffect, hidePreviewButton, hidePreviewBackground, movableBaseForView, infoContainer, contactPhoto, contactNameLabel, callStateLabel, contactIdLabel, cancelCallButton, headerGradientView, controlsStackView, callingWidgetsContainer, brokerPopoverVC;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500132
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400133@synthesize renderConnections;
Kateryna Kostiuk00dcbff2019-07-11 15:42:13 -0400134CVPixelBufferPoolRef pixelBufferPoolDistantView;
135CVPixelBufferRef pixelBufferDistantView;
136CVPixelBufferPoolRef pixelBufferPoolPreview;
137CVPixelBufferRef pixelBufferPreview;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500138
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400139/* update call and conversation info
140 * set info for chat view
141 * connect signals
142 */
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400143-(void) setCurrentCall:(const QString&)callUid
144 conversation:(const QString&)convUid
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400145 account:(const lrc::api::account::Info*)account
146 avModel:(lrc::api::AVModel *)avModel;
Alexandre Lisionc5148052015-03-04 15:10:35 -0500147{
Olivier Soldano994971f2017-12-05 16:30:12 -0500148 if(account == nil)
149 return;
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400150
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400151 mediaModel = avModel;
Olivier Soldano994971f2017-12-05 16:30:12 -0500152 auto* callModel = account->callModel.get();
Alexandre Lisionc5148052015-03-04 15:10:35 -0500153
Olivier Soldano994971f2017-12-05 16:30:12 -0500154 if (not callModel->hasCall(callUid)){
155 callUid_.clear();
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400156 confUid_.clear();
Alexandre Lision2db8f472015-07-22 15:05:46 -0400157 return;
158 }
Olivier Soldano994971f2017-12-05 16:30:12 -0500159 callUid_ = callUid;
160 convUid_ = convUid;
161 accountInfo_ = account;
Kateryna Kostiuk3541ae22020-08-17 12:26:14 -0400162 auto convIt = getConversationFromUid(convUid_, *accountInfo_->conversationModel);
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400163 confUid_ = convIt->confId;
Anthony Léonard4b0935f2017-12-26 12:05:22 -0500164 [self.chatVC setConversationUid:convUid model:account->conversationModel.get()];
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400165 [self connectSignals];
166}
167
168-(void) connectSignals {
169 auto* callModel = accountInfo_->callModel.get();
170 auto* convModel = accountInfo_->conversationModel.get();
171 //monitor for updated call state
172 QObject::disconnect(self.callStateChanged);
173 self.callStateChanged = QObject::connect(callModel,
174 &lrc::api::NewCallModel::callStatusChanged,
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400175 [self](const QString& callId) {
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400176 if ([self isCurrentCall: callId]) {
177 [self updateCall];
178 }
179 });
180 /* monitor media for messaging text messaging */
181 QObject::disconnect(self.messageConnection);
182 self.messageConnection = QObject::connect(convModel,
183 &lrc::api::ConversationModel::interactionStatusUpdated,
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400184 [self] (const QString& convUid,
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400185 uint64_t msgId,
186 lrc::api::interaction::Info msg) {
187 if (msg.type == lrc::api::interaction::Type::TEXT) {
188 if(not [[self splitView] isSubviewCollapsed:[[[self splitView] subviews] objectAtIndex: 1]]){
189 return;
190 }
191 [self uncollapseRightView];
192 }
193 });
194 //monitor for updated profile
195 QObject::disconnect(self.profileUpdatedConnection);
196 self.profileUpdatedConnection =
197 QObject::connect(accountInfo_->contactModel.get(),
198 &lrc::api::ContactModel::contactAdded,
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400199 [self](const QString &contactUri) {
Kateryna Kostiuk3541ae22020-08-17 12:26:14 -0400200 auto convIt = getConversationFromUid(convUid_, *accountInfo_->conversationModel.get());
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400201 if (convIt == accountInfo_->conversationModel->allFilteredConversations().end()) {
202 return;
203 }
204 if (convIt->participants.empty()) {
205 return;
206
207 }
208 auto& contact = accountInfo_->contactModel->getContact(convIt->participants[0]);
209 if (contact.profileInfo.type == lrc::api::profile::Type::RING && contact.profileInfo.uri == contactUri)
210 accountInfo_->conversationModel->makePermanent(convUid_);
211 [contactPhoto setImage: [self getContactImageOfSize:120.0 withDefaultAvatar:YES]];
212 [self.delegate conversationInfoUpdatedFor:convUid_];
213 [self setBackground];
214 });
215 [self connectVideoSignals];
216}
217
218-(void) updatePendingCalls {
219 for (NSView *view in callingWidgetsContainer.subviews) {
220 view.removeFromSuperview;
221 }
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400222 NSDictionary * calls = connectingCalls[callUid_.toNSString()];
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400223 for (NSViewController * callView in calls.allValues) {
224 [self.callingWidgetsContainer addView: callView.view inGravity:NSStackViewGravityBottom];
225 }
Alexandre Lisionc5148052015-03-04 15:10:35 -0500226}
227
Kateryna Kostiuk88a6ee82019-09-10 17:55:08 -0400228-(void) setUpButtons:(lrc::api::call::Info&)callInfo isRecording:(BOOL) isRecording {
229 muteAudioButton.image = callInfo.audioMuted ? [NSImage imageNamed:@"ic_action_mute_audio.png"] :
230 [NSImage imageNamed:@"ic_action_audio.png"];
231 muteVideoButton.image = callInfo.videoMuted ? [NSImage imageNamed:@"ic_action_mute_video.png"] :
232 [NSImage imageNamed:@"ic_action_video.png"];
233 [muteVideoButton setHidden: callInfo.isAudioOnly ? YES: NO];
234 if (isRecording) {
235 [recordOnOffButton startBlinkAnimationfrom:[NSColor buttonBlinkColorColor] to:[NSColor whiteColor] scaleFactor: 1 duration: 1.5];
236 } else {
237 [recordOnOffButton stopBlinkAnimation];
238 }
239}
240
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400241- (void) setUpPreviewFrame {
Kateryna Kostiuk6891d4f2019-09-19 17:44:33 -0400242 CGPoint previewOrigin = CGPointMake(self.videoView.frame.size.width - PREVIEW_WIDTH - PREVIEW_MARGIN, PREVIEW_MARGIN);
243 movableBaseForView.frame = CGRectMake(previewOrigin.x, previewOrigin.y, PREVIEW_WIDTH, PREVIEW_HEIGHT);
Kateryna Kostiuk6891d4f2019-09-19 17:44:33 -0400244 self.movableBaseForView.movable = true;
245 previewView.frame = movableBaseForView.bounds;
Kateryna Kostiuk2aa39232019-10-10 11:55:11 -0400246 hidePreviewBackground.frame = [self frameForExpendPreviewButton];
Kateryna Kostiuke9eb38b2020-03-23 14:33:08 -0400247 if ([hidePreviewButton respondsToSelector:@selector(contentTintColor)]) {
248 hidePreviewButton.contentTintColor = [NSColor blackColor];
249 }
Kateryna Kostiuk6891d4f2019-09-19 17:44:33 -0400250}
251
Alexandre Lisionc5148052015-03-04 15:10:35 -0500252- (void)awakeFromNib
253{
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400254 [self.view setWantsLayer:YES];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500255
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400256 renderConnections = [[RendererConnectionsHolder alloc] init];
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400257
Alexandre Lisionf47a2562015-06-15 15:48:29 -0400258 [loadingIndicator setColor:[NSColor whiteColor]];
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400259 [loadingIndicator setNumberOfLines:200];
260 [loadingIndicator setWidthOfLine:4];
261 [loadingIndicator setLengthOfLine:4];
262 [loadingIndicator setInnerMargin:59];
Alexandre Lisionf47a2562015-06-15 15:48:29 -0400263
Alexandre Lisiona1eee3c2015-08-10 13:44:51 -0400264 [self.videoView setCallDelegate:self];
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400265 [bluerBackgroundEffect setWantsLayer:YES];
Kateryna Kostiuk89398b62018-11-20 16:45:04 -0500266 [backgroundImage setWantsLayer: YES];
267 backgroundImage.layer.contentsGravity = kCAGravityResizeAspectFill;
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400268 movableBaseForView.wantsLayer = YES;
Kateryna Kostiuk2aa39232019-10-10 11:55:11 -0400269 movableBaseForView.shadow = [[NSShadow alloc] init];
270 movableBaseForView.layer.shadowOpacity = 0.6;
271 movableBaseForView.layer.shadowColor = [[NSColor blackColor] CGColor];
272 movableBaseForView.layer.shadowOffset = NSMakeSize(0, -3);
273 movableBaseForView.layer.shadowRadius = 10;
274 previewView.wantsLayer = YES;
275 previewView.layer.cornerRadius = 5;
276 previewView.layer.masksToBounds = true;
277 hidePreviewBackground.wantsLayer = YES;
278 hidePreviewBackground.layer.cornerRadius = 5;
279 hidePreviewBackground.layer.maskedCorners = kCALayerMinXMinYCorner;
280 hidePreviewBackground.layer.masksToBounds = true;
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400281 movableBaseForView.hostingView = self.videoView;
282 [movableBaseForView setAutoresizingMask: NSViewNotSizable | NSViewMaxXMargin | NSViewMaxYMargin | NSViewMinXMargin | NSViewMinYMargin];
283 [previewView setAutoresizingMask: NSViewNotSizable | NSViewMaxXMargin | NSViewMaxYMargin | NSViewMinXMargin | NSViewMinYMargin];
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400284 connectingCalls = [[NSMutableDictionary alloc] init];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500285}
286
Anthony Léonard66a050c2018-01-03 16:32:34 -0500287-(void) updateDurationLabel
288{
289 if (accountInfo_ != nil) {
290 auto* callModel = accountInfo_->callModel.get();
291 if (callModel->hasCall(callUid_)) {
292 auto& callStatus = callModel->getCall(callUid_).status;
293 if (callStatus != lrc::api::call::Status::ENDED &&
294 callStatus != lrc::api::call::Status::TERMINATING &&
295 callStatus != lrc::api::call::Status::INVALID) {
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400296 [timeSpentLabel setStringValue:callModel->getFormattedCallDuration(callUid_).toNSString()];
Anthony Léonard66a050c2018-01-03 16:32:34 -0500297 return;
298 }
299 }
300 }
301
302 // If call is not running anymore or accountInfo_ is not set for any reason
303 // we stop the refresh loop
304 [refreshDurationTimer invalidate];
305 refreshDurationTimer = nil;
Anthony Léonard66a050c2018-01-03 16:32:34 -0500306}
307
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400308-(void) updateCall
Alexandre Lisionc5148052015-03-04 15:10:35 -0500309{
Olivier Soldano994971f2017-12-05 16:30:12 -0500310 if (accountInfo_ == nil)
311 return;
Alexandre Lisionbb5dbcd2015-07-09 16:36:47 -0400312
Olivier Soldano994971f2017-12-05 16:30:12 -0500313 auto* callModel = accountInfo_->callModel.get();
314 if (not callModel->hasCall(callUid_)) {
315 return;
316 }
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500317
Olivier Soldano994971f2017-12-05 16:30:12 -0500318 auto currentCall = callModel->getCall(callUid_);
Kateryna Kostiuk3541ae22020-08-17 12:26:14 -0400319 auto convIt = getConversationFromUid(convUid_, *accountInfo_->conversationModel);
320 if (conversationExists(convIt, *accountInfo_->conversationModel)) {
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400321 NSString* bestName = bestNameForConversation(*convIt, *accountInfo_->conversationModel);
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400322 [contactNameLabel setStringValue:bestName];
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400323 NSString* ringID = bestIDForConversation(*convIt, *accountInfo_->conversationModel);
324 if([bestName isEqualToString:ringID]) {
325 ringID = @"";
326 }
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400327 [contactIdLabel setStringValue:ringID];
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400328 }
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400329 [self setupContactInfo:contactPhoto];
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400330 confUid_ = convIt->confId;
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400331 [muteAudioButton setHidden:!confUid_.isEmpty()];
332 [muteVideoButton setHidden:!confUid_.isEmpty()];
333 [recordOnOffButton setHidden:!confUid_.isEmpty()];
334 [holdOnOffButton setHidden:!confUid_.isEmpty()];
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400335
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400336 [timeSpentLabel setStringValue:callModel->getFormattedCallDuration(callUid_).toNSString()];
Anthony Léonard66a050c2018-01-03 16:32:34 -0500337 if (refreshDurationTimer == nil)
338 refreshDurationTimer = [NSTimer scheduledTimerWithTimeInterval:1.0
339 target:self
340 selector:@selector(updateDurationLabel)
341 userInfo:nil
342 repeats:YES];
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400343 [self setBackground];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500344
Olivier Soldano994971f2017-12-05 16:30:12 -0500345 using Status = lrc::api::call::Status;
Kateryna Kostiuk88a6ee82019-09-10 17:55:08 -0400346 if (currentCall.status == Status::PAUSED) {
347 [holdOnOffButton startBlinkAnimationfrom:[NSColor buttonBlinkColorColor] to:[NSColor whiteColor] scaleFactor: 1.0 duration: 1.5];
348 } else {
349 [holdOnOffButton stopBlinkAnimation];
350 }
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400351
Kateryna Kostiuka7404812019-10-28 12:24:46 -0400352 [self setUpButtons: currentCall isRecording: (callModel->isRecording([self getcallID]) || mediaModel->getAlwaysRecord())];
353
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400354 [videoView setShouldAcceptInteractions: currentCall.status == Status::IN_PROGRESS];
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400355 callStateLabel.stringValue = currentCall.status == Status::INCOMING_RINGING ? @"wants to talk to you" : to_string(currentCall.status).toNSString();
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400356 loadingIndicator.hidden = (currentCall.status == Status::SEARCHING ||
357 currentCall.status == Status::CONNECTING ||
358 currentCall.status == Status::OUTGOING_RINGING) ? NO : YES;
359 pickUpButton.hidden = (currentCall.status == Status::INCOMING_RINGING) ? NO : YES;
360 callStateLabel.hidden = (currentCall.status == Status::IN_PROGRESS) ? YES : NO;
361 cancelCallButton.hidden = (currentCall.status == Status::IN_PROGRESS ||
362 currentCall.status == Status::PAUSED) ? YES : NO;
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400363 callingWidgetsContainer.hidden = (currentCall.status == Status::IN_PROGRESS) ? NO : YES;
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400364
Olivier Soldano994971f2017-12-05 16:30:12 -0500365 switch (currentCall.status) {
366 case Status::SEARCHING:
Olivier Soldano994971f2017-12-05 16:30:12 -0500367 case Status::CONNECTING:
Olivier Soldano994971f2017-12-05 16:30:12 -0500368 case Status::OUTGOING_RINGING:
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400369 case Status::INCOMING_RINGING:
370 [infoContainer setHidden: NO];
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400371 [headerContainer setHidden:YES];
Kateryna Kostiuk2aa39232019-10-10 11:55:11 -0400372 [headerGradientView setHidden:YES];
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400373 [controlsPanel setHidden:YES];
Kateryna Kostiuk2aa39232019-10-10 11:55:11 -0400374 [controlsStackView setHidden:YES];
Kateryna Kostiuk06681682020-05-07 20:50:56 -0400375 [self.distantView fillWithBlack];
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400376 [self.previewView fillWithBlack];
377 [hidePreviewBackground setHidden:YES];
378 [self.previewView setHidden: YES];
Kateryna Kostiuk06681682020-05-07 20:50:56 -0400379 [self.distantView setHidden: YES];
380 self.previewView.videoRunning = NO;
381 self.distantView.videoRunning = NO;
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400382 [backgroundImage setHidden:NO];
383 [bluerBackgroundEffect setHidden:NO];
Olivier Soldano994971f2017-12-05 16:30:12 -0500384 break;
Olivier Soldano994971f2017-12-05 16:30:12 -0500385 case Status::PAUSED:
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400386 [infoContainer setHidden: NO];
387 [headerContainer setHidden:NO];
Kateryna Kostiuk2aa39232019-10-10 11:55:11 -0400388 [headerGradientView setHidden:NO];
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400389 [controlsPanel setHidden:NO];
Kateryna Kostiuk2aa39232019-10-10 11:55:11 -0400390 [controlsStackView setHidden:NO];
Kateryna Kostiuk00dcbff2019-07-11 15:42:13 -0400391 [backgroundImage setHidden:NO];
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400392 [bluerBackgroundEffect setHidden:NO];
393 if(!currentCall.isAudioOnly) {
Kateryna Kostiuk06681682020-05-07 20:50:56 -0400394 [self.distantView fillWithBlack];
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400395 [self.previewView fillWithBlack];
396 [hidePreviewBackground setHidden:YES];
397 [self.previewView setHidden: YES];
Kateryna Kostiuk06681682020-05-07 20:50:56 -0400398 [self.distantView setHidden: YES];
399 self.previewView.videoRunning = NO;
400 self.distantView.videoRunning = NO;
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400401 }
Kateryna Kostiuk00dcbff2019-07-11 15:42:13 -0400402 break;
Olivier Soldano994971f2017-12-05 16:30:12 -0500403 case Status::INACTIVE:
Kateryna Kostiuk00dcbff2019-07-11 15:42:13 -0400404 if(currentCall.isAudioOnly) {
405 [self setUpAudioOnlyView];
406 } else {
407 [self setUpVideoCallView];
408 }
409 break;
Olivier Soldano994971f2017-12-05 16:30:12 -0500410 case Status::IN_PROGRESS:
“Kateryna”414738e2020-04-07 11:44:35 -0400411 callModel->setCurrentCall([self getcallID]);
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400412 [headerContainer setHidden:NO];
Kateryna Kostiuk2aa39232019-10-10 11:55:11 -0400413 [headerGradientView setHidden:NO];
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400414 [controlsPanel setHidden:NO];
Kateryna Kostiuk2aa39232019-10-10 11:55:11 -0400415 [controlsStackView setHidden:NO];
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400416 if(currentCall.isAudioOnly) {
417 [self setUpAudioOnlyView];
418 } else {
419 [self setUpVideoCallView];
420 }
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400421 break;
Olivier Soldano994971f2017-12-05 16:30:12 -0500422 case Status::CONNECTED:
Olivier Soldano994971f2017-12-05 16:30:12 -0500423 break;
424 case Status::ENDED:
425 case Status::TERMINATING:
426 case Status::INVALID:
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400427 case Status::PEER_BUSY:
428 case Status::TIMEOUT:
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400429 connectingCalls[callUid_.toNSString()] = nil;
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400430 //[self cleanUp];
431 [self.delegate callFinished];
Olivier Soldano994971f2017-12-05 16:30:12 -0500432 break;
433 }
Alexandre Lision4d9905e2016-01-22 12:01:36 -0500434}
435
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400436-(void) setUpVideoCallView {
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400437 [previewView fillWithBlack];
Kateryna Kostiuk06681682020-05-07 20:50:56 -0400438 [self.distantView fillWithBlack];
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400439 [previewView setHidden: NO];
Kateryna Kostiuk06681682020-05-07 20:50:56 -0400440 [self.distantView setHidden:NO];
441 [hidePreviewBackground setHidden: !self.previewView.videoRunning];
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400442 [bluerBackgroundEffect setHidden:YES];
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400443 [backgroundImage setHidden:YES];
Kateryna Kostiuk06681682020-05-07 20:50:56 -0400444 self.previewView.videoRunning = true;
445 self.distantView.videoRunning = true;
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400446}
447
448-(void) setUpAudioOnlyView {
Kateryna Kostiuk00dcbff2019-07-11 15:42:13 -0400449 [self.previewView setHidden: YES];
Kateryna Kostiuk06681682020-05-07 20:50:56 -0400450 [self.distantView setHidden: YES];
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400451 [hidePreviewBackground setHidden: YES];
452 [bluerBackgroundEffect setHidden:NO];
453 [backgroundImage setHidden:NO];
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400454}
455
456-(void) setBackground {
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400457 NSImage *image= [self getContactImageOfSize:120.0 withDefaultAvatar:NO];
458 if(image) {
Kateryna Kostiuk89398b62018-11-20 16:45:04 -0500459 CIImage * ciImage = [[CIImage alloc] initWithData:[image TIFFRepresentation]];
460 CIContext *context = [[CIContext alloc] init];
461 CIFilter *clamp = [CIFilter filterWithName:@"CIAffineClamp"];
462 [clamp setValue:[NSAffineTransform transform] forKey:@"inputTransform"];
463 [clamp setValue:ciImage forKey: kCIInputImageKey];
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400464 CIFilter* bluerFilter = [CIFilter filterWithName:@"CIGaussianBlur"];
465 [bluerFilter setDefaults];
Kateryna Kostiuk89398b62018-11-20 16:45:04 -0500466 [bluerFilter setValue:[NSNumber numberWithFloat: 9] forKey:@"inputRadius"];
467 [bluerFilter setValue:[clamp valueForKey:kCIOutputImageKey] forKey: kCIInputImageKey];
468 CIImage *result = [bluerFilter valueForKey:kCIOutputImageKey];
469 CGRect extent = [result extent];
470 CGImageRef cgImage = [context createCGImage:result fromRect: [ciImage extent]];
471 NSImage *bluredImage = [[NSImage alloc] initWithCGImage:cgImage size:NSSizeFromCGSize(CGSizeMake(image.size.width, image.size.height))];
472 backgroundImage.layer.contents = bluredImage;
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400473 [backgroundImage setHidden:NO];
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400474 [bluerBackgroundEffect setFillColor:[NSColor darkGrayColor]];
475 [bluerBackgroundEffect setAlphaValue:0.6];
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400476 } else {
Kateryna Kostiuk2aa39232019-10-10 11:55:11 -0400477 contactNameLabel.textColor = [NSColor textColor];
Kateryna Kostiuk2aa39232019-10-10 11:55:11 -0400478 contactIdLabel.textColor = [NSColor textColor];
479 callStateLabel.textColor = [NSColor textColor];
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400480 backgroundImage.layer.contents = nil;
Kateryna Kostiuk2aa39232019-10-10 11:55:11 -0400481 [bluerBackgroundEffect setFillColor:[NSColor windowBackgroundColor]];
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400482 [bluerBackgroundEffect setAlphaValue:1];
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400483 [backgroundImage setHidden:YES];
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400484 }
485}
486
Kateryna Kostiuk133364b2018-10-31 11:36:08 -0400487-(NSImage *) getContactImageOfSize: (double) size withDefaultAvatar:(BOOL) shouldDrawDefault {
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400488 auto* convModel = accountInfo_->conversationModel.get();
Kateryna Kostiuk3541ae22020-08-17 12:26:14 -0400489 auto convIt = getConversationFromUid(convUid_, *convModel);
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400490 if (convIt == convModel->allFilteredConversations().end()) {
491 return nil;
492 }
493 if(shouldDrawDefault) {
494 auto& imgManip = reinterpret_cast<Interfaces::ImageManipulationDelegate&>(GlobalInstances::pixmapManipulator());
495 QVariant photo = imgManip.conversationPhoto(*convIt, *accountInfo_, QSize(size, size), NO);
496 return QtMac::toNSImage(qvariant_cast<QPixmap>(photo));
497 }
498 auto contact = accountInfo_->contactModel->getContact(convIt->participants[0]);
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400499 NSData *imageData = [[NSData alloc] initWithBase64EncodedString:contact.profileInfo.avatar.toNSString() options:NSDataBase64DecodingIgnoreUnknownCharacters];
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400500 return [[NSImage alloc] initWithData:imageData];
501}
502
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400503-(void) setupContactInfo:(NSImageView*)imageView
504{
505 [imageView setImage: [self getContactImageOfSize:120.0 withDefaultAvatar:YES]];
506}
507
Olivier Soldano994971f2017-12-05 16:30:12 -0500508-(void)collapseRightView
509{
510 NSView *right = [[splitView subviews] objectAtIndex:1];
511 NSView *left = [[splitView subviews] objectAtIndex:0];
512 NSRect leftFrame = [left frame];
513 [right setHidden:YES];
514 [splitView display];
515}
516
Alexandre Lisionc5148052015-03-04 15:10:35 -0500517-(void) connectVideoSignals
518{
Olivier Soldano994971f2017-12-05 16:30:12 -0500519 if (accountInfo_ == nil)
520 return;
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400521 [self connectRenderer];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500522}
523
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400524-(void) connectRenderer
Alexandre Lisionc5148052015-03-04 15:10:35 -0500525{
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400526 QObject::disconnect(renderConnections.frameUpdated);
527 QObject::disconnect(renderConnections.stopped);
528 QObject::disconnect(renderConnections.started);
529 renderConnections.started =
530 QObject::connect(mediaModel,
531 &lrc::api::AVModel::rendererStarted,
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400532 [=](const QString& id) {
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400533 if (id == lrc::api::video::PREVIEW_RENDERER_ID) {
534 [self.previewView setHidden:NO];
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400535 [hidePreviewBackground setHidden: NO];
Kateryna Kostiuk06681682020-05-07 20:50:56 -0400536 self.previewView.videoRunning = true;
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400537 } else if ([self isCurrentCall: id]) {
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400538 [self mouseIsMoving: NO];
Kateryna Kostiuk06681682020-05-07 20:50:56 -0400539 self.distantView.videoRunning = true;
540 [self.distantView setHidden:NO];
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400541 [bluerBackgroundEffect setHidden:YES];
542 [backgroundImage setHidden:YES];
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400543 }
Alexandre Lisionc5148052015-03-04 15:10:35 -0500544 });
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400545 renderConnections.stopped =
546 QObject::connect(mediaModel,
547 &lrc::api::AVModel::rendererStopped,
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400548 [=](const QString& id) {
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400549 if (id == lrc::api::video::PREVIEW_RENDERER_ID) {
550 [self.previewView setHidden:YES];
Kateryna Kostiuk06681682020-05-07 20:50:56 -0400551 self.previewView.videoRunning = false;
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400552 } else if ([self isCurrentCall: id]) {
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400553 [self mouseIsMoving: YES];
Kateryna Kostiuk06681682020-05-07 20:50:56 -0400554 self.distantView.videoRunning = false;
555 [self.distantView setHidden:YES];
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400556 [bluerBackgroundEffect setHidden:NO];
557 [backgroundImage setHidden:NO];
Kateryna Kostiuk00dcbff2019-07-11 15:42:13 -0400558 }
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400559 });
560 renderConnections.frameUpdated =
561 QObject::connect(mediaModel,
562 &lrc::api::AVModel::frameUpdated,
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400563 [=](const QString& id) {
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400564 if (id == lrc::api::video::PREVIEW_RENDERER_ID) {
565 auto renderer = &mediaModel->getRenderer(lrc::api::video::PREVIEW_RENDERER_ID);
566 if(!renderer->isRendering()) {
567 return;
568 }
Kateryna Kostiuk06681682020-05-07 20:50:56 -0400569 [hidePreviewBackground setHidden: !self.previewView.videoRunning];
570 [self rendererPreview: renderer];
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400571 } else if ([self isCurrentCall: id]) {
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400572 auto renderer = &mediaModel->getRenderer(id);
573 if(!renderer->isRendering()) {
574 return;
575 }
Kateryna Kostiuk06681682020-05-07 20:50:56 -0400576 [self rendererDistantView: renderer];
Kateryna Kostiuk732b4062018-11-28 09:59:28 -0500577 }
Alexandre Lisionc5148052015-03-04 15:10:35 -0500578 });
579}
580
Kateryna Kostiuk06681682020-05-07 20:50:56 -0400581-(void) rendererDistantView: (const lrc::api::video::Renderer*)renderer {
Kateryna Kostiuk00dcbff2019-07-11 15:42:13 -0400582 @autoreleasepool {
583 auto framePtr = renderer->currentAVFrame();
584 auto frame = framePtr.get();
585 if(!frame || !frame->width || !frame->height) {
586 return;
587 }
588 auto frameSize = CGSizeMake(frame->width, frame->height);
589 auto rotation = 0;
590 if (auto matrix = av_frame_get_side_data(frame, AV_FRAME_DATA_DISPLAYMATRIX)) {
591 const int32_t* data = reinterpret_cast<int32_t*>(matrix->data);
592 rotation = av_display_rotation_get(data);
593 }
594 if (frame->data[3] != NULL && (CVPixelBufferRef)frame->data[3]) {
Kateryna Kostiuk06681682020-05-07 20:50:56 -0400595 [self.distantView renderWithPixelBuffer: (CVPixelBufferRef)frame->data[3]
Kateryna Kostiuk00dcbff2019-07-11 15:42:13 -0400596 size: frameSize
597 rotation: rotation
598 fillFrame: false];
599 }
600 if (CVPixelBufferRef pixelBuffer = [self getBufferForDistantViewFromFrame:frame]) {
Kateryna Kostiuk06681682020-05-07 20:50:56 -0400601 [self.distantView renderWithPixelBuffer: pixelBuffer
Kateryna Kostiuk00dcbff2019-07-11 15:42:13 -0400602 size: frameSize
603 rotation: rotation
604 fillFrame: false];
605 }
Kateryna Kostiukbcf24e92018-11-20 10:09:06 -0500606 }
Anthony Léonard14e7bf32017-06-08 08:13:16 -0400607}
608
Kateryna Kostiuk06681682020-05-07 20:50:56 -0400609-(void) rendererPreview: (const lrc::api::video::Renderer*)renderer {
610 @autoreleasepool {
611 auto framePtr = renderer->currentAVFrame();
612 auto frame = framePtr.get();
613 if(!frame || !frame->width || !frame->height) {
614 return;
615 }
616 auto frameSize = CGSizeMake(frame->width, frame->height);
617 auto rotation = 0;
618 if (auto matrix = av_frame_get_side_data(frame, AV_FRAME_DATA_DISPLAYMATRIX)) {
619 const int32_t* data = reinterpret_cast<int32_t*>(matrix->data);
620 rotation = av_display_rotation_get(data);
621 }
622 if (frame->data[3] != NULL && (CVPixelBufferRef)frame->data[3]) {
623 [self.previewView renderWithPixelBuffer: (CVPixelBufferRef)frame->data[3]
624 size: frameSize
625 rotation: rotation
626 fillFrame: false];
627 }
628 if (CVPixelBufferRef pixelBuffer = [self getBufferForPreviewFromFrame:frame]) {
629 [self.previewView renderWithPixelBuffer: pixelBuffer
630 size: frameSize
631 rotation: rotation
632 fillFrame: true];
633 }
634 }
635}
636
Kateryna Kostiuk00dcbff2019-07-11 15:42:13 -0400637-(CVPixelBufferRef) getBufferForPreviewFromFrame:(const AVFrame*)frame {
Kateryna Kostiukc5fd3b92019-07-24 10:12:44 -0400638 [VideoCommon fillPixelBuffr:&pixelBufferPreview fromFrame:frame bufferPool:&pixelBufferPoolPreview];
639 CVPixelBufferRef buffer = pixelBufferPreview;
640 return buffer;
Kateryna Kostiuk00dcbff2019-07-11 15:42:13 -0400641}
642
643-(CVPixelBufferRef) getBufferForDistantViewFromFrame:(const AVFrame*)frame {
Kateryna Kostiukc5fd3b92019-07-24 10:12:44 -0400644 [VideoCommon fillPixelBuffr:&pixelBufferDistantView fromFrame:frame bufferPool:&pixelBufferPoolDistantView];
645 CVPixelBufferRef buffer = pixelBufferDistantView;
646 return buffer;
Kateryna Kostiuk00dcbff2019-07-11 15:42:13 -0400647}
648
Alexandre Lisionc5148052015-03-04 15:10:35 -0500649- (void) initFrame
650{
651 [self.view setFrame:self.view.superview.bounds];
652 [self.view setHidden:YES];
653 self.view.layer.position = self.view.frame.origin;
Alexandre Lisionbb5dbcd2015-07-09 16:36:47 -0400654 [self collapseRightView];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500655}
656
657# pragma private IN/OUT animations
658
Olivier Soldano994971f2017-12-05 16:30:12 -0500659-(void)uncollapseRightView
660{
661 NSView *left = [[splitView subviews] objectAtIndex:0];
662 NSView *right = [[splitView subviews] objectAtIndex:1];
663 [right setHidden:NO];
664
665 CGFloat dividerThickness = [splitView dividerThickness];
666
667 // get the different frames
668 NSRect leftFrame = [left frame];
669 NSRect rightFrame = [right frame];
670
671 leftFrame.size.width = (leftFrame.size.width - rightFrame.size.width - dividerThickness);
672 rightFrame.origin.x = leftFrame.size.width + dividerThickness;
673 [left setFrameSize:leftFrame.size];
674 [right setFrame:rightFrame];
675 [splitView display];
676
677 [self.chatVC takeFocus];
678}
679
Alexandre Lisionc5148052015-03-04 15:10:35 -0500680-(void) cleanUp
681{
Anthony Léonard5c287642018-02-21 15:54:19 -0500682 if(self.splitView.isInFullScreenMode)
683 [self.splitView exitFullScreenModeWithOptions:nil];
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400684 QObject::disconnect(renderConnections.frameUpdated);
685 QObject::disconnect(renderConnections.started);
686 QObject::disconnect(renderConnections.stopped);
Anthony Léonardc0013bb2018-02-20 16:23:02 -0500687 QObject::disconnect(self.messageConnection);
Alexandre Lision883719f2015-10-22 17:37:45 -0400688
Alexandre Lision4baba4c2016-02-11 13:00:57 -0500689 [self.chatButton setPressed:NO];
Alexandre Lision883719f2015-10-22 17:37:45 -0400690 [self collapseRightView];
Alexandre Lision57227772016-01-15 17:19:36 -0500691
Alexandre Lision57227772016-01-15 17:19:36 -0500692 [timeSpentLabel setStringValue:@""];
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400693 [contactIdLabel setStringValue:@""];
694 [contactNameLabel setStringValue:@""];
695 [contactPhoto setImage:nil];
Kateryna Kostiuk81afce72018-10-30 16:40:50 -0400696 //background view
697 [bluerBackgroundEffect setHidden:NO];
698 [backgroundImage setHidden:NO];
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400699 backgroundImage.layer.contents = nil;
Kateryna Kostiuk00dcbff2019-07-11 15:42:13 -0400700 [self.previewView setHidden:YES];
Kateryna Kostiuk06681682020-05-07 20:50:56 -0400701 [self.distantView setHidden:YES];
Kateryna Kostiuk9e9f7822019-09-27 11:29:45 -0400702
703 contactNameLabel.textColor = [NSColor highlightColor];
704 contactNameLabel.textColor = [NSColor highlightColor];
705 contactIdLabel.textColor = [NSColor highlightColor];
706 callStateLabel.textColor = [NSColor highlightColor];
Kateryna Kostiuk5acaefd2020-03-25 11:14:25 -0400707 [self.chatVC clearData];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500708}
709
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400710/*
711 * update ui
712*/
713
Andreas Traczykecdc4fa2018-03-22 16:11:47 -0400714-(void) setupCallView
715{
716 if (accountInfo_ == nil)
717 return;
718
719 auto* callModel = accountInfo_->callModel.get();
Andreas Traczykecdc4fa2018-03-22 16:11:47 -0400720
Andreas Traczykecdc4fa2018-03-22 16:11:47 -0400721 /* check if text media is already present */
722 if(not callModel->hasCall(callUid_))
723 return;
724
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400725 // when call comes in we want to show the controls/header
726 [self mouseIsMoving: YES];
Andreas Traczykecdc4fa2018-03-22 16:11:47 -0400727 [loadingIndicator setAnimates:YES];
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400728 auto currentCall = callModel->getCall([self getcallID]);
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400729 [previewView setHidden: YES];
730 [self setUpPreviewFrame];
731 [self updatePendingCalls];
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400732 [self updateCall];
Andreas Traczykecdc4fa2018-03-22 16:11:47 -0400733}
734
735-(void) showWithAnimation:(BOOL)animate
736{
737 if (!animate) {
738 [self.view setHidden:NO];
739 [self setupCallView];
740 return;
741 }
742
743 CGRect frame = CGRectOffset(self.view.superview.bounds, -self.view.superview.bounds.size.width, 0);
744 [self.view setHidden:NO];
745
746 [CATransaction begin];
747 CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
748 [animation setFromValue:[NSValue valueWithPoint:frame.origin]];
749 [animation setToValue:[NSValue valueWithPoint:self.view.superview.bounds.origin]];
750 [animation setDuration:0.2f];
751 [animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]];
752 [CATransaction setCompletionBlock:^{
753 [self setupCallView];
754 }];
755
756 [self.view.layer addAnimation:animation forKey:animation.keyPath];
757 [CATransaction commit];
758}
759
760-(void) hideWithAnimation:(BOOL)animate
Alexandre Lisionc5148052015-03-04 15:10:35 -0500761{
Alexandre Lisionc5148052015-03-04 15:10:35 -0500762 if(self.view.frame.origin.x < 0) {
Alexandre Lisionc5148052015-03-04 15:10:35 -0500763 return;
764 }
765
Andreas Traczykecdc4fa2018-03-22 16:11:47 -0400766 if (!animate) {
767 [self.view setHidden:YES];
768 return;
769 }
770
Alexandre Lisionc5148052015-03-04 15:10:35 -0500771 CGRect frame = CGRectOffset(self.view.frame, -self.view.frame.size.width, 0);
772 [CATransaction begin];
773 CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
774 [animation setFromValue:[NSValue valueWithPoint:self.view.frame.origin]];
775 [animation setToValue:[NSValue valueWithPoint:frame.origin]];
776 [animation setDuration:0.2f];
Alexandre Lision22d615b2016-01-25 12:54:34 -0500777 [animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500778
779 [CATransaction setCompletionBlock:^{
780 [self.view setHidden:YES];
Alexandre Lisionef6333a2015-03-24 12:30:31 -0400781 // first make sure everything is disconnected
Alexandre Lisionc5148052015-03-04 15:10:35 -0500782 [self cleanUp];
Olivier Soldano994971f2017-12-05 16:30:12 -0500783// if (currentCall_) {
784// [self animateIn];
785// }
Alexandre Lisionc5148052015-03-04 15:10:35 -0500786 }];
787 [self.view.layer addAnimation:animation forKey:animation.keyPath];
Alexandre Lisiona1c6d752015-06-23 12:27:38 -0400788
789 [self.view.layer setPosition:frame.origin];
Alexandre Lisionc5148052015-03-04 15:10:35 -0500790 [CATransaction commit];
791}
792
793/**
794 * Debug purpose
795 */
796-(void) dumpFrame:(CGRect) frame WithName:(NSString*) name
797{
798 NSLog(@"frame %@ : %f %f %f %f \n\n",name ,frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
799}
800
Alexandre Lision58cab672015-06-09 15:25:40 -0400801#pragma mark - Button methods
802
Alexandre Lisionc5148052015-03-04 15:10:35 -0500803- (IBAction)hangUp:(id)sender {
Olivier Soldano994971f2017-12-05 16:30:12 -0500804 if (accountInfo_ == nil)
805 return;
806
807 auto* callModel = accountInfo_->callModel.get();
Kateryna Kostiuk28b99be2019-11-18 14:54:08 -0500808 callModel->hangUp(callUid_);
Alexandre Lisionc5148052015-03-04 15:10:35 -0500809}
810
811- (IBAction)accept:(id)sender {
Olivier Soldano994971f2017-12-05 16:30:12 -0500812 if (accountInfo_ == nil)
813 return;
814
Anthony Léonardf584cc52018-01-19 12:00:19 -0500815 // If we accept a conversation with a non trusted contact, we first accept it
Kateryna Kostiuk3541ae22020-08-17 12:26:14 -0400816 auto convIt = getConversationFromUid(convUid_, *accountInfo_->conversationModel.get());
817 if (convIt != accountInfo_->conversationModel->allFilteredConversations().end()) {
Anthony Léonardf584cc52018-01-19 12:00:19 -0500818 auto& contact = accountInfo_->contactModel->getContact(convIt->participants[0]);
819 if (contact.profileInfo.type == lrc::api::profile::Type::PENDING)
820 accountInfo_->conversationModel->makePermanent(convUid_);
821 }
822
Olivier Soldano994971f2017-12-05 16:30:12 -0500823 auto* callModel = accountInfo_->callModel.get();
824
825 callModel->accept(callUid_);
Alexandre Lisionc5148052015-03-04 15:10:35 -0500826}
827
828- (IBAction)toggleRecording:(id)sender {
Olivier Soldano994971f2017-12-05 16:30:12 -0500829 if (accountInfo_ == nil)
830 return;
831
832 auto* callModel = accountInfo_->callModel.get();
Olivier Soldano994971f2017-12-05 16:30:12 -0500833 callModel->toggleAudioRecord(callUid_);
Kateryna Kostiuk88a6ee82019-09-10 17:55:08 -0400834 if (callModel->isRecording(callUid_)) {
835 [recordOnOffButton startBlinkAnimationfrom:[NSColor buttonBlinkColorColor] to:[NSColor whiteColor] scaleFactor: 1 duration: 1.5];
836 } else {
837 [recordOnOffButton stopBlinkAnimation];
838 }
Alexandre Lisionc5148052015-03-04 15:10:35 -0500839}
840
841- (IBAction)toggleHold:(id)sender {
Olivier Soldano994971f2017-12-05 16:30:12 -0500842 if (accountInfo_ == nil)
843 return;
844
845 auto* callModel = accountInfo_->callModel.get();
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400846 callModel->togglePause([self getcallID]);
Alexandre Lisionc5148052015-03-04 15:10:35 -0500847}
848
Alexandre Lision62005312016-01-28 15:55:16 -0500849- (IBAction)showDialpad:(id)sender {
850 AppDelegate* appDelegate = (AppDelegate *)[[NSApplication sharedApplication] delegate];
851 [appDelegate showDialpad];
852}
853
Alexandre Lision58cab672015-06-09 15:25:40 -0400854-(IBAction)toggleChat:(id)sender;
855{
856 BOOL rightViewCollapsed = [[self splitView] isSubviewCollapsed:[[[self splitView] subviews] objectAtIndex: 1]];
857 if (rightViewCollapsed) {
858 [self uncollapseRightView];
Alexandre Lision58cab672015-06-09 15:25:40 -0400859 } else {
860 [self collapseRightView];
861 }
Alexandre Lision62005312016-01-28 15:55:16 -0500862 [chatButton setPressed:rightViewCollapsed];
Alexandre Lision58cab672015-06-09 15:25:40 -0400863}
864
Alexandre Lisiond18fa272015-06-15 11:18:03 -0400865- (IBAction)muteAudio:(id)sender
866{
Olivier Soldano994971f2017-12-05 16:30:12 -0500867 if (accountInfo_ == nil)
868 return;
869
870 auto* callModel = accountInfo_->callModel.get();
Kateryna Kostiuk54d76972018-06-07 15:45:07 -0400871 auto currentCall = callModel->getCall(callUid_);
872 if (currentCall.audioMuted) {
873 muteAudioButton.image = [NSImage imageNamed:@"ic_action_audio.png"];
874 } else {
875 muteAudioButton.image = [NSImage imageNamed:@"ic_action_mute_audio.png"];
876 }
Olivier Soldano994971f2017-12-05 16:30:12 -0500877 callModel->toggleMedia(callUid_, lrc::api::NewCallModel::Media::AUDIO);
Alexandre Lisiond18fa272015-06-15 11:18:03 -0400878}
879
880- (IBAction)muteVideo:(id)sender
881{
Olivier Soldano994971f2017-12-05 16:30:12 -0500882 if (accountInfo_ == nil)
883 return;
Olivier Soldano994971f2017-12-05 16:30:12 -0500884 auto* callModel = accountInfo_->callModel.get();
Kateryna Kostiuk54d76972018-06-07 15:45:07 -0400885 auto currentCall = callModel->getCall(callUid_);
886 if(!currentCall.isAudioOnly) {
887 if (currentCall.videoMuted) {
888 muteVideoButton.image = [NSImage imageNamed:@"ic_action_video.png"];
889 } else {
890 muteVideoButton.image = [NSImage imageNamed:@"ic_action_mute_video.png"];
891 }
892 }
Olivier Soldano994971f2017-12-05 16:30:12 -0500893 callModel->toggleMedia(callUid_, lrc::api::NewCallModel::Media::VIDEO);
Alexandre Lisiond18fa272015-06-15 11:18:03 -0400894}
Alexandre Lision883719f2015-10-22 17:37:45 -0400895
896- (IBAction)toggleTransferView:(id)sender {
Kateryna Kostiuk1ba5a012018-12-12 17:07:38 -0500897
Alexandre Lisionf23ec5a2015-07-16 11:24:06 -0400898}
Alexandre Lisiond18fa272015-06-15 11:18:03 -0400899
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500900- (IBAction)toggleAddParticipantView:(id)sender {
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400901 if (brokerPopoverVC != nullptr) {
902 [brokerPopoverVC performClose:self];
903 brokerPopoverVC = NULL;
904 } else {
905 auto* contactSelectorVC = [[ChooseContactVC alloc] initWithNibName:@"ChooseContactVC" bundle:nil];
906 auto* convModel = accountInfo_->conversationModel.get();
907 [contactSelectorVC setConversationModel:convModel andCurrentConversation: convUid_];
908 contactSelectorVC.delegate = self;
909 brokerPopoverVC = [[NSPopover alloc] init];
910 [brokerPopoverVC setContentSize:contactSelectorVC.view.frame.size];
911 [brokerPopoverVC setContentViewController:contactSelectorVC];
912 [brokerPopoverVC setAnimates:YES];
913 [brokerPopoverVC setBehavior:NSPopoverBehaviorTransient];
914 [brokerPopoverVC setDelegate:self];
915 [brokerPopoverVC showRelativeToRect:[sender bounds] ofView:sender preferredEdge:NSMinYEdge];
916 }
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500917}
Kateryna Kostiuk4db61092019-10-17 16:57:40 -0400918
Kateryna Kostiuk6891d4f2019-09-19 17:44:33 -0400919- (IBAction)hidePreview:(id)sender {
920 CGRect previewFrame = previewView.frame;
Kateryna Kostiuk28b99be2019-11-18 14:54:08 -0500921 CGRect newPreviewFrame;
Kateryna Kostiuk2aa39232019-10-10 11:55:11 -0400922 if (previewFrame.size.width > HIDE_PREVIEW_BUTTON_SIZE) {
Kateryna Kostiuk6891d4f2019-09-19 17:44:33 -0400923 self.movableBaseForView.movable = false;
924 newPreviewFrame = self.getVideoPreviewCollapsedSize;
Kateryna Kostiuk6891d4f2019-09-19 17:44:33 -0400925 hidePreviewButton.image = [NSImage imageNamed: NSImageNameTouchBarEnterFullScreenTemplate];
926 } else {
927 self.movableBaseForView.movable = true;
928 newPreviewFrame = CGRectMake(0, 0, PREVIEW_WIDTH, PREVIEW_HEIGHT);
Kateryna Kostiuk6891d4f2019-09-19 17:44:33 -0400929 hidePreviewButton.image = [NSImage imageNamed: NSImageNameTouchBarExitFullScreenTemplate];
930 }
931 [NSAnimationContext runAnimationGroup:^(NSAnimationContext * _Nonnull context) {
932 context.duration = 0.2f;
933 context.timingFunction = [CAMediaTimingFunction functionWithName: kCAMediaTimingFunctionEaseOut];
934 previewView.animator.frame = newPreviewFrame;
935 } completionHandler: nil];
Kateryna Kostiuk6891d4f2019-09-19 17:44:33 -0400936}
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500937
Alexandre Lision58cab672015-06-09 15:25:40 -0400938#pragma mark - NSSplitViewDelegate
939
940/* 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.
941 */
942- (BOOL)splitView:(NSSplitView *)splitView shouldCollapseSubview:(NSView *)subview forDoubleClickOnDividerAtIndex:(NSInteger)dividerIndex;
943{
944 NSView* rightView = [[splitView subviews] objectAtIndex:1];
945 return ([subview isEqual:rightView]);
946}
947
948
949- (BOOL)splitView:(NSSplitView *)splitView canCollapseSubview:(NSView *)subview;
950{
951 NSView* rightView = [[splitView subviews] objectAtIndex:1];
952 return ([subview isEqual:rightView]);
953}
954
955
Alexandre Lisiona1eee3c2015-08-10 13:44:51 -0400956# pragma mark - CallnDelegate
Alexandre Lision58cab672015-06-09 15:25:40 -0400957
958- (void) callShouldToggleFullScreen
959{
960 if(self.splitView.isInFullScreenMode)
961 [self.splitView exitFullScreenModeWithOptions:nil];
962 else {
963 NSApplicationPresentationOptions options = NSApplicationPresentationDefault +NSApplicationPresentationAutoHideDock +
964 NSApplicationPresentationAutoHideMenuBar + NSApplicationPresentationAutoHideToolbar;
965 NSDictionary *opts = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithUnsignedInt:options],
966 NSFullScreenModeApplicationPresentationOptions, nil];
967
968 [self.splitView enterFullScreenMode:[NSScreen mainScreen] withOptions:opts];
969 }
970}
971
Alexandre Lisiona1eee3c2015-08-10 13:44:51 -0400972-(void) mouseIsMoving:(BOOL) move
973{
Kateryna Kostiuk2aa39232019-10-10 11:55:11 -0400974 [[controlsPanel animator] setAlphaValue:move];// fade out
975 [[controlsStackView animator] setAlphaValue:move];
Alexandre Lisiona1eee3c2015-08-10 13:44:51 -0400976 [[headerContainer animator] setAlphaValue:move];
Kateryna Kostiuk2aa39232019-10-10 11:55:11 -0400977 [[headerGradientView animator] setAlphaValue:move];
Alexandre Lisiona1eee3c2015-08-10 13:44:51 -0400978}
979
Kateryna Kostiuk89398b62018-11-20 16:45:04 -0500980- (BOOL)splitView:(NSSplitView *)splitView shouldHideDividerAtIndex:(NSInteger)dividerIndex
981{
982 return YES;
983}
984
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -0400985-(void) screenShare {
986 NSScreen *mainScreen = [NSScreen mainScreen];
987 NSRect screenFrame = mainScreen.frame;
988 QRect captureRect = QRect(screenFrame.origin.x, screenFrame.origin.y, screenFrame.size.width, screenFrame.size.height);
989 mediaModel->setDisplay(0, screenFrame.origin.x, screenFrame.origin.y, screenFrame.size.width, screenFrame.size.height);
990}
991-(void) switchToDevice:(int)deviceID {
992 auto devices = mediaModel->getDevices();
993 auto device = devices[deviceID];
994 mediaModel->switchInputTo(device);
995}
996
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400997-(QVector<QString>) getDeviceList {
998 QVector<QString> devicesVector;
Kateryna Kostiuk64533102019-10-29 15:34:29 -0400999 for (auto device : mediaModel->getDevices()) {
1000 try {
1001 auto settings = mediaModel->getDeviceSettings(device);
Kateryna Kostiukc867eb92020-03-08 13:15:17 -04001002 devicesVector.append(settings.name);
Kateryna Kostiuk64533102019-10-29 15:34:29 -04001003 } catch (...) {}
1004 }
1005 return devicesVector;
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -04001006}
1007
Kateryna Kostiuk32cf6be2019-10-28 12:22:45 -04001008-(NSString*) getDefaultDeviceName {
1009 auto type = mediaModel->getCurrentRenderedDevice(callUid_).type;
1010 switch (type) {
1011 case lrc::api::video::DeviceType::CAMERA:
Kateryna Kostiuk64533102019-10-29 15:34:29 -04001012 try {
1013 auto device = mediaModel->getCurrentRenderedDevice(callUid_).name;
1014 auto settings = mediaModel->getDeviceSettings(device);
Kateryna Kostiukc867eb92020-03-08 13:15:17 -04001015 return settings.name.toNSString();
Kateryna Kostiuk64533102019-10-29 15:34:29 -04001016 } catch (...) {}
Kateryna Kostiuk32cf6be2019-10-28 12:22:45 -04001017 case lrc::api::video::DeviceType::DISPLAY:
1018 return NSLocalizedString(@"Share screen", @"Contextual menu entry");
1019 default:
1020 return @"";
1021 }
1022}
1023
Kateryna Kostiukc867eb92020-03-08 13:15:17 -04001024-(void) switchToFile:(QString)uri {
1025 mediaModel->setInputFile(uri);
Kateryna Kostiuk5d90c3b2019-07-18 12:03:52 -04001026}
1027
Kateryna Kostiuk6891d4f2019-09-19 17:44:33 -04001028-(CGRect) getVideoPreviewCollapsedSize {
1029 CGPoint origin;
1030 switch (movableBaseForView.closestCorner) {
1031 case TOP_LEFT:
Kateryna Kostiuk2aa39232019-10-10 11:55:11 -04001032 origin = CGPointMake(0, movableBaseForView.frame.size.height - HIDE_PREVIEW_BUTTON_SIZE);
Kateryna Kostiuk6891d4f2019-09-19 17:44:33 -04001033 break;
1034 case BOTTOM_LEFT:
1035 origin = CGPointMake(0, 0);
1036 break;
1037 case TOP_RIGHT:
Kateryna Kostiuk2aa39232019-10-10 11:55:11 -04001038 origin = CGPointMake(movableBaseForView.frame.size.width - HIDE_PREVIEW_BUTTON_SIZE, movableBaseForView.frame.size.height - HIDE_PREVIEW_BUTTON_SIZE);
Kateryna Kostiuk6891d4f2019-09-19 17:44:33 -04001039 break;
1040 case BOTTOM_RIGHT:
Kateryna Kostiuk2aa39232019-10-10 11:55:11 -04001041 origin = CGPointMake(movableBaseForView.frame.size.width - HIDE_PREVIEW_BUTTON_SIZE, 0);
Kateryna Kostiuk6891d4f2019-09-19 17:44:33 -04001042 break;
1043 }
Kateryna Kostiuk2aa39232019-10-10 11:55:11 -04001044 return CGRectMake(origin.x, origin.y, HIDE_PREVIEW_BUTTON_SIZE, HIDE_PREVIEW_BUTTON_SIZE);
Kateryna Kostiuk6891d4f2019-09-19 17:44:33 -04001045}
1046
Kateryna Kostiuk2aa39232019-10-10 11:55:11 -04001047-(CGRect) frameForExpendPreviewButton {
1048 CGPoint origin = CGPointMake(self.previewView.frame.size.width - HIDE_PREVIEW_BUTTON_SIZE,
1049 self.previewView.frame.size.height - HIDE_PREVIEW_BUTTON_SIZE);
1050 return CGRectMake(origin.x, origin.y, HIDE_PREVIEW_BUTTON_SIZE, HIDE_PREVIEW_BUTTON_SIZE);
Kateryna Kostiuk6891d4f2019-09-19 17:44:33 -04001051}
1052
Kateryna Kostiuk4db61092019-10-17 16:57:40 -04001053# pragma mark -ChooseContactVCDelegate
1054
Kateryna Kostiukc867eb92020-03-08 13:15:17 -04001055-(void)callToContact:(const QString&)contactUri convUID:(const QString&)convID {
Kateryna Kostiuk4db61092019-10-17 16:57:40 -04001056 if (brokerPopoverVC != nullptr) {
1057 [brokerPopoverVC performClose:self];
1058 brokerPopoverVC = NULL;
1059 }
1060 auto* callModel = accountInfo_->callModel.get();
1061 auto currentCall = callModel->getCall([self getcallID]);
1062 auto* convModel = accountInfo_->conversationModel.get();
1063 auto newCall = callModel->callAndAddParticipant(contactUri,
1064 [self getcallID],
1065 currentCall.isAudioOnly);
1066 [self addPreviewForContactUri:contactUri call: newCall];
1067}
1068
Kateryna Kostiukc867eb92020-03-08 13:15:17 -04001069-(void)joinCall:(const QString&)callId {
Kateryna Kostiuk4db61092019-10-17 16:57:40 -04001070 if (brokerPopoverVC != nullptr) {
1071 [brokerPopoverVC performClose:self];
1072 brokerPopoverVC = NULL;
1073 }
1074 auto* callModel = accountInfo_->callModel.get();
1075 callModel->joinCalls([self getcallID], callId);
1076}
1077
1078# pragma mark -CallInConferenceVCDelegate
1079
Kateryna Kostiukc867eb92020-03-08 13:15:17 -04001080-(void)removePreviewForContactUri:(const QString&)uri forCall:(const QString&) callId {
1081 NSMutableDictionary * calls = connectingCalls[callId.toNSString()];
Kateryna Kostiuk4db61092019-10-17 16:57:40 -04001082 if (!calls) {
1083 return;
1084 }
Kateryna Kostiukc867eb92020-03-08 13:15:17 -04001085 NSViewController *callView = calls[uri.toNSString()];
Kateryna Kostiuk4db61092019-10-17 16:57:40 -04001086 if (!callView) {
1087 return;
1088 }
Kateryna Kostiukc867eb92020-03-08 13:15:17 -04001089 calls[uri.toNSString()] = nil;
Kateryna Kostiuk4db61092019-10-17 16:57:40 -04001090 [self.callingWidgetsContainer removeView:callView.view];
1091}
1092
Kateryna Kostiukc867eb92020-03-08 13:15:17 -04001093-(void)addPreviewForContactUri:(const QString&)uri call:(const QString&)callId {
1094 NSMutableDictionary *calls = connectingCalls[callUid_.toNSString()];
Kateryna Kostiuk4db61092019-10-17 16:57:40 -04001095 if (!calls) {
1096 calls = [[NSMutableDictionary alloc] init];
1097 }
Kateryna Kostiukc867eb92020-03-08 13:15:17 -04001098 if (calls[uri.toNSString()]) {
Kateryna Kostiuk4db61092019-10-17 16:57:40 -04001099 return;
1100 }
1101 CallInConferenceVC *callingView = [self callingViewForCallId: callId];
Kateryna Kostiukc867eb92020-03-08 13:15:17 -04001102 calls[uri.toNSString()] = callingView;
1103 connectingCalls[callUid_.toNSString()] = calls;
Kateryna Kostiuk4db61092019-10-17 16:57:40 -04001104 [self.callingWidgetsContainer addView:callingView.view inGravity:NSStackViewGravityBottom];
1105 [self.callingWidgetsContainer updateConstraints];
1106 [self.callingWidgetsContainer updateLayer];
1107 [self.callingWidgetsContainer setNeedsDisplay:YES];
1108}
1109
Kateryna Kostiukc867eb92020-03-08 13:15:17 -04001110-(CallInConferenceVC*) callingViewForCallId:(const QString&)callId {
Kateryna Kostiuk4db61092019-10-17 16:57:40 -04001111 CallInConferenceVC *callView = [[CallInConferenceVC alloc]
1112 initWithNibName:@"CallInConferenceVC"
1113 bundle:nil
1114 callId:callId
1115 accountInfo:accountInfo_];
1116 callView.delegate = self;
1117 callView.initiatorCallId = callUid_;
1118 return callView;
1119}
1120
Kateryna Kostiukc867eb92020-03-08 13:15:17 -04001121-(const QString&)getcallID {
1122 return confUid_.isEmpty() ? callUid_ : confUid_;
Kateryna Kostiuk4db61092019-10-17 16:57:40 -04001123}
1124
Kateryna Kostiukc867eb92020-03-08 13:15:17 -04001125-(bool)isCurrentCall:(const QString&)callId {
Kateryna Kostiuk4db61092019-10-17 16:57:40 -04001126 return (callId == confUid_ || callId == callUid_);
1127}
1128
1129#pragma mark Popover delegate
1130
1131- (void)popoverWillClose:(NSNotification *)notification
1132{
1133 if (brokerPopoverVC != nullptr) {
1134 [brokerPopoverVC performClose:self];
1135 brokerPopoverVC = NULL;
1136 }
1137}
Alexandre Lisionc5148052015-03-04 15:10:35 -05001138@end