From 89edc6ad21d53f10c6825cbb8e3f1a233c093cbe Mon Sep 17 00:00:00 2001 From: Alexandre Lision <alexandre.lision@savoirfairelinux.com> Date: Mon, 9 Nov 2015 11:30:47 -0500 Subject: [PATCH] conference: first implementation This commit adds conferences management - create conference by joining two ongoing calls/conferences - create conference by calling a new peer and joining him to the ongoing call/conference - hanging up conferences This commit relies on CallModel and RecenModel selection models interactions to update call view and Smartlist row selected. Change-Id: Ib9f6b9b870e66c8ccfb5115ad6fdb592c625eb58 Tuleap: #114 --- CMakeLists.txt | 2 + data/dark/ic_action_add_participant.png | Bin 0 -> 538 bytes data/dark/ic_action_merge_calls.png | Bin 0 -> 261 bytes src/BrokerVC.h | 2 +- src/BrokerVC.mm | 70 +++++++++- src/CurrentCallVC.mm | 118 +++++++++++----- src/HistoryVC.mm | 3 +- src/PersonsVC.mm | 1 + src/QNSTreeController.h | 1 + src/QNSTreeController.mm | 6 + src/SmartViewVC.mm | 46 +++--- ui/Base.lproj/Broker.strings | 12 ++ ui/Base.lproj/CurrentCall.strings | 41 ++++-- ui/Base.lproj/CurrentCall.xib | 177 +++++++++++++++++------- 14 files changed, 365 insertions(+), 114 deletions(-) create mode 100644 data/dark/ic_action_add_participant.png create mode 100644 data/dark/ic_action_merge_calls.png create mode 100644 ui/Base.lproj/Broker.strings diff --git a/CMakeLists.txt b/CMakeLists.txt index a8d14c11..06934235 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -188,6 +188,8 @@ ${CMAKE_CURRENT_SOURCE_DIR}/data/dark/ic_call_received.png ${CMAKE_CURRENT_SOURCE_DIR}/data/dark/ic_call_missed.png ${CMAKE_CURRENT_SOURCE_DIR}/data/dark/ic_call_made.png ${CMAKE_CURRENT_SOURCE_DIR}/data/dark/ic_action_transfer.png +${CMAKE_CURRENT_SOURCE_DIR}/data/dark/ic_action_add_participant.png +${CMAKE_CURRENT_SOURCE_DIR}/data/dark/ic_action_merge_calls.png ${CMAKE_CURRENT_SOURCE_DIR}/data/dark/ancrage.png ${CMAKE_CURRENT_SOURCE_DIR}/data/dark/audio.png ${CMAKE_CURRENT_SOURCE_DIR}/data/dark/ic_person_add.png diff --git a/data/dark/ic_action_add_participant.png b/data/dark/ic_action_add_participant.png new file mode 100644 index 0000000000000000000000000000000000000000..ca85742220b0e976f9e5370163cf82e3f3237ce1 GIT binary patch literal 538 zcmeAS@N?(olHy`uVBq!ia0y~yVDJE84i*LmhW}5h&oD4BKJ;{P45?szd(J*PI8o&I z$NUWOKn*L+kd0H676$)i){2mF(YgDD)uh?$`lAQh1tN2HX*5lG6tVV&0;?eF)N{K+ zE+341<D0y;le0hX`9rx$uYLX69{rs2vAj*cdSdZ8%jYqTmeX!7@od%-P4nD+Fg$7# z-!+xjEm!tFXW6KH<*Sv1_)o_R$IUJu$$MQYpcdK})601zvF`QNsK!#K>DA6}mPVaD zD`>Q?Wyj6JvjP)d=UE!RuuF<sf6a0BOvm{Gi>tQsWu>uQ75M!%OZLhM(UOD@j#tkt z=<fhYtV&_K>pbO4maNHaNt5OsOT%9){J3EH+;n4j)mDD3p!YK-8}wPYMX#4?nKM1? z)r648OdGAMw(<(O-dnkTyN`hM)8%n*n~$W*eQb@de{amc)8$s_DwC^OGARd|-w03L zEBD0F*=OScq3oOq7Z$l5V$0UqctFHCgMoEj(X7PV3j|NCnIN$1j+pioNk{EZy}4mK zk12L92oAZS`seZ6poc1%##=a9q->t~*gGcMsD3H%mtamRpZHbs@m|)mo1I^LESsTT zHo@v+)H(Sr9xpzNb=qFYmV2K0UG~Z|nMYkw=O-QJZaQe|E))J*%Th(nF}kBR>#rZ* s!52q1+=}`iIf1=$0x0n36xTB>U3x@{tFGfF0|Nttr>mdKI;Vst03^rvL;wH) literal 0 HcmV?d00001 diff --git a/data/dark/ic_action_merge_calls.png b/data/dark/ic_action_merge_calls.png new file mode 100644 index 0000000000000000000000000000000000000000..84fe9617aeaadf6a0627c23cd2482877d1e80295 GIT binary patch literal 261 zcmeAS@N?(olHy`uVBq!ia0y~yVDJE84i*LmhW}5h&oD4BobhyV45?szdu}7|VFMnQ zz_2e;_x5+cZQRtk=o#}n2??fRhj*K&^6AehKKIx2w~gkx>U-;sNPbqxEKuMq#ECQu z6->?Z)F(Q!Nv2Ey5dqn=xj4?1vac*`lX|}N*vTJu#oIh|&zb6nTI^|5In=0f=;65& zVSXREg0z>{Rl59ZbB>%a%hGh^ROiS)Sx+6T!Y4D>O0;efJM!jhh0)`P(}~||j5sq5 p+auMa|BG$D`Tx4*^Eq+y&YtXLd~1$AVqjok@O1TaS?83{1OROtWK{qF literal 0 HcmV?d00001 diff --git a/src/BrokerVC.h b/src/BrokerVC.h index 9e6190fe..aaf21b7f 100644 --- a/src/BrokerVC.h +++ b/src/BrokerVC.h @@ -23,7 +23,7 @@ enum class BrokerMode { TRANSFER = 0, - //CONFERENCE + CONFERENCE, }; - (instancetype)initWithMode:(BrokerMode) m; diff --git a/src/BrokerVC.mm b/src/BrokerVC.mm index bb374c9b..52c555fb 100644 --- a/src/BrokerVC.mm +++ b/src/BrokerVC.mm @@ -23,6 +23,7 @@ #import <QItemSelectionModel> #import <QtMacExtras/qmacfunctions.h> #import <QPixmap> +#import <QMimeData> //LRC #import <recentmodel.h> @@ -103,7 +104,13 @@ NSInteger const TXT_BUTTON_TAG = 500; [_smartView bind:@"sortDescriptors" toObject:_treeController withKeyPath:@"sortDescriptors" options:nil]; [_smartView bind:@"selectionIndexPaths" toObject:_treeController withKeyPath:@"selectionIndexPaths" options:nil]; [_smartView setTarget:self]; - [_smartView setDoubleAction:@selector(placeTransfer:)]; + + if ([self mode] == BrokerMode::TRANSFER) { + [_smartView setDoubleAction:@selector(placeTransfer:)]; + } else { + [_smartView setDoubleAction:@selector(addParticipant:)]; + } + } // ------------------------------------------------------------------------------- @@ -145,6 +152,60 @@ NSInteger const TXT_BUTTON_TAG = 500; CallModel::instance().transfer(current, number); } +// ------------------------------------------------------------------------------- +// place a call to the future participant on click on Person or ContactMethod +// ------------------------------------------------------------------------------- +- (void)addParticipant:(id)sender +{ + auto current = CallModel::instance().selectedCall(); + + if (!current || [_treeController selectedNodes].count == 0) + return; + + QModelIndex qIdx = [_treeController toQIdx:[_treeController selectedNodes][0]]; + auto originIdx = RecentModel::instance().peopleProxy()->mapToSource(_recentFilterModel->mapToSource(qIdx)); + + auto participant = RecentModel::instance().getActiveCall(originIdx); + if (participant) { //join this call with the current one + QModelIndexList source_list; + source_list << CallModel::instance().getIndex(current); + auto idx_call_dest = CallModel::instance().getIndex(participant); + auto mimeData = CallModel::instance().mimeData(source_list); + auto action = Call::DropAction::Conference; + mimeData->setProperty("dropAction", action); + + if (CallModel::instance().dropMimeData(mimeData, Qt::MoveAction, idx_call_dest.row(), idx_call_dest.column(), idx_call_dest.parent())) { + NSLog(@"OK"); + } else { + NSLog(@"could not drop mime data"); + } + return; + } + + auto contactmethods = RecentModel::instance().getContactMethods(originIdx); + if (contactmethods.size() > 0) { // Before calling check if we properly extracted at least one contact method + auto call = CallModel::instance().dialingCall(contactmethods.first()); + call->setParentCall(current); + call << Call::Action::ACCEPT; + CallModel::instance().selectCall(call); + } +} + +// ------------------------------------------------------------------------------- +// place a call to the future participant with entered URI +// ------------------------------------------------------------------------------- +- (void) addParticipantFromUri:(NSString*) uri +{ + auto current = CallModel::instance().selectedCall(); + if (!current) + return; + auto number = PhoneDirectoryModel::instance().getNumber(QString::fromNSString(uri)); + auto dialing = CallModel::instance().dialingCall(number); + dialing->setParentCall(current); + dialing << Call::Action::ACCEPT; + CallModel::instance().selectCall(dialing); +} + #pragma mark - NSOutlineViewDelegate methods // ------------------------------------------------------------------------------- @@ -216,7 +277,12 @@ NSInteger const TXT_BUTTON_TAG = 500; { if (commandSelector == @selector(insertNewline:)) { if([fieldEditor.textStorage.string isNotEqualTo:@""]) { - [self transferTo:fieldEditor.textStorage.string]; + + if ([self mode] == BrokerMode::TRANSFER) { + [self transferTo:fieldEditor.textStorage.string]; + } else { + [self addParticipantFromUri:fieldEditor.textStorage.string]; + } return YES; } } diff --git a/src/CurrentCallVC.mm b/src/CurrentCallVC.mm index c4dc684f..ca20354c 100644 --- a/src/CurrentCallVC.mm +++ b/src/CurrentCallVC.mm @@ -22,7 +22,9 @@ #import <call.h> #import <callmodel.h> +#import <recentmodel.h> #import <useractionmodel.h> +#import <QMimeData> #import <contactmethod.h> #import <qabstractitemmodel.h> #import <QItemSelectionModel> @@ -52,8 +54,14 @@ @interface CurrentCallVC () <NSPopoverDelegate, ContactLinkedDelegate> +// Header info +@property (unsafe_unretained) IBOutlet NSView* headerContainer; @property (unsafe_unretained) IBOutlet NSTextField* personLabel; @property (unsafe_unretained) IBOutlet NSTextField* stateLabel; +@property (unsafe_unretained) IBOutlet NSTextField* timeSpentLabel; + +// Call Controls +@property (unsafe_unretained) IBOutlet NSView* controlsPanel; @property (unsafe_unretained) IBOutlet NSButton* holdOnOffButton; @property (unsafe_unretained) IBOutlet NSButton* hangUpButton; @property (unsafe_unretained) IBOutlet NSButton* recordOnOffButton; @@ -62,17 +70,19 @@ @property (unsafe_unretained) IBOutlet NSButton* muteVideoButton; @property (unsafe_unretained) IBOutlet NSButton* addContactButton; @property (unsafe_unretained) IBOutlet NSButton* transferButton; -@property (unsafe_unretained) IBOutlet NSView* headerContainer; +@property (unsafe_unretained) IBOutlet NSButton* addParticipantButton; +@property (unsafe_unretained) IBOutlet NSButton* chatButton; @property (unsafe_unretained) IBOutlet ITProgressIndicator *loadingIndicator; -@property (unsafe_unretained) IBOutlet NSTextField* timeSpentLabel; -@property (unsafe_unretained) IBOutlet NSView* controlsPanel; +// Join call panel +@property (unsafe_unretained) IBOutlet NSView* joinPanel; +@property (unsafe_unretained) IBOutlet NSButton* mergeCallsButton; + @property (unsafe_unretained) IBOutlet NSSplitView* splitView; -@property (unsafe_unretained) IBOutlet NSButton* chatButton; @property (strong) NSPopover* addToContactPopover; -@property (strong) NSPopover* transferPopoverVC; +@property (strong) NSPopover* brokerPopoverVC; @property (strong) IBOutlet ChatVC* chatVC; @property QHash<int, NSButton*> actionHash; @@ -93,7 +103,7 @@ @implementation CurrentCallVC @synthesize personLabel, actionHash, stateLabel, holdOnOffButton, hangUpButton, - recordOnOffButton, pickUpButton, chatButton, transferButton, timeSpentLabel, + recordOnOffButton, pickUpButton, chatButton, transferButton, addParticipantButton, timeSpentLabel, muteVideoButton, muteAudioButton, controlsPanel, headerContainer, videoView, videoLayer, previewLayer, previewView, splitView, loadingIndicator; @@ -124,6 +134,8 @@ if (!callIdx.isValid()) { return; } + auto current = CallModel::instance().getCall(callIdx); + [personLabel setStringValue:callIdx.data(Qt::DisplayRole).toString().toNSString()]; [timeSpentLabel setStringValue:callIdx.data((int)Call::Role::Length).toString().toNSString()]; @@ -135,9 +147,10 @@ // Default values for this views [loadingIndicator setHidden:YES]; - [self.chatButton setHidden:YES]; [videoView setShouldAcceptInteractions:NO]; + [self.controlsPanel setHidden:current->hasParentCall()]; + [self.joinPanel setHidden:!current->hasParentCall()]; [stateLabel setStringValue:callIdx.data((int)Call::Role::HumanStateName).toString().toNSString()]; switch (state) { @@ -154,9 +167,17 @@ break; case Call::State::RINGING: break; + case Call::State::CONFERENCE: + [videoView setShouldAcceptInteractions:YES]; + [self.chatButton setHidden:NO]; + [self.addParticipantButton setHidden:NO]; + [self.transferButton setHidden:YES]; + break; case Call::State::CURRENT: [videoView setShouldAcceptInteractions:YES]; [self.chatButton setHidden:NO]; + [self.addParticipantButton setHidden:NO]; + [self.transferButton setHidden:NO]; break; case Call::State::HOLD: break; @@ -177,18 +198,12 @@ [self.view setWantsLayer:YES]; [self.view setLayer:[CALayer layer]]; - [controlsPanel setWantsLayer:YES]; - [controlsPanel setLayer:[CALayer layer]]; - [controlsPanel.layer setZPosition:2.0]; - [controlsPanel.layer setBackgroundColor:[NSColor whiteColor].CGColor]; - actionHash[ (int)UserActionModel::Action::ACCEPT] = pickUpButton; actionHash[ (int)UserActionModel::Action::HOLD ] = holdOnOffButton; actionHash[ (int)UserActionModel::Action::RECORD] = recordOnOffButton; actionHash[ (int)UserActionModel::Action::HANGUP] = hangUpButton; actionHash[ (int)UserActionModel::Action::MUTE_AUDIO] = muteAudioButton; actionHash[ (int)UserActionModel::Action::MUTE_VIDEO] = muteVideoButton; - actionHash[ (int)UserActionModel::Action::SERVER_TRANSFER] = transferButton; videoLayer = [CALayer layer]; [videoView setWantsLayer:YES]; @@ -225,15 +240,17 @@ - (void) connect { - QObject::connect(CallModel::instance().selectionModel(), + QObject::connect(RecentModel::instance().selectionModel(), &QItemSelectionModel::currentChanged, [=](const QModelIndex ¤t, const QModelIndex &previous) { - if(!current.isValid()) { + auto call = RecentModel::instance().getActiveCall(current); + if(!current.isValid() || !call) { [self animateOut]; return; } - auto call = CallModel::instance().getCall(current); + CallModel::instance().selectCall(call); + if (call->state() == Call::State::HOLD) { call << Call::Action::HOLD; } @@ -276,6 +293,7 @@ { QModelIndex idx = CallModel::instance().selectionModel()->currentIndex(); Call* call = CallModel::instance().getCall(idx); + QObject::disconnect(self.videoStarted); self.videoStarted = QObject::connect(call, &Call::videoStarted, [=](Video::Renderer* renderer) { @@ -457,10 +475,15 @@ [videoView.layer setContents:nil]; [previewView.layer setContents:nil]; - [self.transferPopoverVC performClose:self]; + [_brokerPopoverVC performClose:self]; [self.addToContactPopover performClose:self]; + [self.chatButton setHidden:YES]; + [self.addParticipantButton setHidden:YES]; + [self.transferButton setHidden:YES]; + [self.chatButton setState:NSOffState]; + [self.mergeCallsButton setState:NSOffState]; [self collapseRightView]; } @@ -469,9 +492,6 @@ NSLog(@"animateOut"); if(self.view.frame.origin.x < 0) { NSLog(@"Already hidden"); - if (CallModel::instance().selectionModel()->currentIndex().isValid()) { - [self animateIn]; - } return; } @@ -487,7 +507,7 @@ [self.view setHidden:YES]; // first make sure everything is disconnected [self cleanUp]; - if (CallModel::instance().selectionModel()->currentIndex().isValid()) { + if (RecentModel::instance().getActiveCall(RecentModel::instance().selectionModel()->currentIndex())) { [self animateIn]; } }]; @@ -602,30 +622,57 @@ } - (IBAction)toggleTransferView:(id)sender { - if (self.transferPopoverVC != nullptr) { - [self.transferPopoverVC performClose:self]; - self.transferPopoverVC = NULL; + if (_brokerPopoverVC != nullptr) { + [_brokerPopoverVC performClose:self]; + _brokerPopoverVC = NULL; [self.transferButton setState:NSOffState]; } else { - auto* transferVC = [[BrokerVC alloc] initWithMode:BrokerMode::TRANSFER]; - self.transferPopoverVC = [[NSPopover alloc] init]; - [self.transferPopoverVC setContentSize:transferVC.view.frame.size]; - [self.transferPopoverVC setContentViewController:transferVC]; - [self.transferPopoverVC setAnimates:YES]; - [self.transferPopoverVC setBehavior:NSPopoverBehaviorTransient]; - [self.transferPopoverVC setDelegate:self]; - [self.transferPopoverVC showRelativeToRect:[sender bounds] ofView:sender preferredEdge:NSMinYEdge]; + auto* brokerVC = [[BrokerVC alloc] initWithMode:BrokerMode::TRANSFER]; + _brokerPopoverVC = [[NSPopover alloc] init]; + [_brokerPopoverVC setContentSize:brokerVC.view.frame.size]; + [_brokerPopoverVC setContentViewController:brokerVC]; + [_brokerPopoverVC setAnimates:YES]; + [_brokerPopoverVC setBehavior:NSPopoverBehaviorTransient]; + [_brokerPopoverVC setDelegate:self]; + [_brokerPopoverVC showRelativeToRect:[sender bounds] ofView:sender preferredEdge:NSMinYEdge]; + [videoView setCallDelegate:nil]; + } +} + +- (IBAction)toggleAddParticipantView:(id)sender { + if (_brokerPopoverVC != nullptr) { + [_brokerPopoverVC performClose:self]; + _brokerPopoverVC = NULL; + [self.addParticipantButton setState:NSOffState]; + } else { + auto* brokerVC = [[BrokerVC alloc] initWithMode:BrokerMode::CONFERENCE]; + _brokerPopoverVC = [[NSPopover alloc] init]; + [_brokerPopoverVC setContentSize:brokerVC.view.frame.size]; + [_brokerPopoverVC setContentViewController:brokerVC]; + [_brokerPopoverVC setAnimates:YES]; + [_brokerPopoverVC setBehavior:NSPopoverBehaviorTransient]; + [_brokerPopoverVC setDelegate:self]; + [_brokerPopoverVC showRelativeToRect:[sender bounds] ofView:sender preferredEdge:NSMinYEdge]; [videoView setCallDelegate:nil]; } } +/** + * Merge current call with its parent call + */ +- (IBAction)mergeCalls:(id)sender +{ + auto current = CallModel::instance().selectedCall(); + current->joinToParent(); +} + #pragma mark - NSPopOverDelegate - (void)popoverWillClose:(NSNotification *)notification { - if (self.transferPopoverVC != nullptr) { - [self.transferPopoverVC performClose:self]; - self.transferPopoverVC = NULL; + if (_brokerPopoverVC != nullptr) { + [_brokerPopoverVC performClose:self]; + _brokerPopoverVC = NULL; } if (self.addToContactPopover != nullptr) { @@ -635,6 +682,7 @@ [self.addContactButton setState:NSOffState]; [self.transferButton setState:NSOffState]; + [self.addParticipantButton setState:NSOffState]; } - (void)popoverDidClose:(NSNotification *)notification diff --git a/src/HistoryVC.mm b/src/HistoryVC.mm index f111ec00..3b17422b 100644 --- a/src/HistoryVC.mm +++ b/src/HistoryVC.mm @@ -98,9 +98,10 @@ NSInteger const DETAILS_TAG = 300; QVariant var = historyProxyModel->data(qIdx, (int)Call::Role::ContactMethod); ContactMethod* m = qvariant_cast<ContactMethod*>(var); if(m){ - Call* c = CallModel::instance().dialingCall(); + auto c = CallModel::instance().dialingCall(); c->setPeerContactMethod(m); c << Call::Action::ACCEPT; + CallModel::instance().selectCall(c); } } } diff --git a/src/PersonsVC.mm b/src/PersonsVC.mm index 170a3c1d..aebe00bc 100644 --- a/src/PersonsVC.mm +++ b/src/PersonsVC.mm @@ -122,6 +122,7 @@ NSInteger const CALL_BUTTON_TAG = 400; Call* c = CallModel::instance().dialingCall(); c->setPeerContactMethod(m); c << Call::Action::ACCEPT; + CallModel::instance().selectCall(c); } } } diff --git a/src/QNSTreeController.h b/src/QNSTreeController.h index 434d6507..9b538895 100644 --- a/src/QNSTreeController.h +++ b/src/QNSTreeController.h @@ -28,5 +28,6 @@ - (id) initWithQModel:(QAbstractItemModel*) model; - (QModelIndex) toQIdx:(NSTreeNode*) node; - (QModelIndex) indexPathtoQIdx:(NSIndexPath*) path; +- (void) setSelectionQModelIndex:(QModelIndex) qIdx; @end diff --git a/src/QNSTreeController.mm b/src/QNSTreeController.mm index 7f7a6f8c..d6322077 100644 --- a/src/QNSTreeController.mm +++ b/src/QNSTreeController.mm @@ -142,6 +142,12 @@ } } +- (void) setSelectionQModelIndex:(QModelIndex) qIdx +{ + NSIndexPath* path = [self qIdxToNSIndexPath:qIdx]; + [self setSelectionIndexPath:path]; +} + - (void)connect { QObject::connect(self->privateQModel, diff --git a/src/SmartViewVC.mm b/src/SmartViewVC.mm index 06b80e97..b08feb7a 100644 --- a/src/SmartViewVC.mm +++ b/src/SmartViewVC.mm @@ -79,6 +79,7 @@ NSInteger const TXT_BUTTON_TAG = 500; [smartView bind:@"sortDescriptors" toObject:treeController withKeyPath:@"sortDescriptors" options:nil]; [smartView bind:@"selectionIndexPaths" toObject:treeController withKeyPath:@"selectionIndexPaths" options:nil]; [smartView setTarget:self]; + [smartView setAction:@selector(selectRow:)]; [smartView setDoubleAction:@selector(placeCall:)]; [smartView setContextMenuDelegate:self]; @@ -94,6 +95,24 @@ NSInteger const TXT_BUTTON_TAG = 500; } }); + QObject::connect(RecentModel::instance().selectionModel(), + &QItemSelectionModel::currentChanged, + [=](const QModelIndex ¤t, const QModelIndex &previous) { + if(!current.isValid()) + return; + + auto proxyIdx = RecentModel::instance().peopleProxy()->mapFromSource(current); + if (proxyIdx.isValid()) { + [treeController setSelectionQModelIndex:proxyIdx]; + + [showContactsButton setState:NO]; + isShowingContacts = NO; + [showHistoryButton setState:NO]; + [tabbar selectTabViewItemAtIndex:0]; + [smartView scrollRowToVisible:proxyIdx.row()]; + } + }); + [self.view setWantsLayer:YES]; [self.view setLayer:[CALayer layer]]; [self.view.layer setBackgroundColor:[NSColor whiteColor].CGColor]; @@ -103,6 +122,13 @@ NSInteger const TXT_BUTTON_TAG = 500; [searchField.layer setBackgroundColor:[NSColor colorWithCalibratedRed:0.949 green:0.949 blue:0.949 alpha:0.9].CGColor]; } +-(void) selectRow:(id)sender +{ + auto qIdx = [treeController toQIdx:[treeController selectedNodes][0]]; + auto proxyIdx = RecentModel::instance().peopleProxy()->mapToSource(qIdx); + RecentModel::instance().selectionModel()->setCurrentIndex(proxyIdx, QItemSelectionModel::ClearAndSelect); +} + - (void)placeCall:(id)sender { QModelIndex qIdx = [treeController toQIdx:[treeController selectedNodes][0]]; @@ -131,12 +157,10 @@ NSInteger const TXT_BUTTON_TAG = 500; // Before calling check if we properly extracted a contact method and that // there is NOT already an ongoing call for this index (e.g: no children for this node) if(m && !RecentModel::instance().peopleProxy()->index(0, 0, qIdx).isValid()){ - Call* c = CallModel::instance().dialingCall(); + auto c = CallModel::instance().dialingCall(); c->setPeerContactMethod(m); c << Call::Action::ACCEPT; - - [smartView deselectAll:nil]; - [smartView selectRowIndexes:[[NSIndexSet alloc] initWithIndex:0] byExtendingSelection:NO]; + CallModel::instance().selectCall(c); } } @@ -184,27 +208,15 @@ NSInteger const TXT_BUTTON_TAG = 500; return NO; } - // ------------------------------------------------------------------------------- // outlineViewSelectionDidChange:notification // ------------------------------------------------------------------------------- - (void)outlineViewSelectionDidChange:(NSNotification *)notification { if ([treeController selectedNodes].count <= 0) { - CallModel::instance().selectionModel()->clearCurrentIndex(); + RecentModel::instance().selectionModel()->clearCurrentIndex(); return; } - - QModelIndex qIdx = [treeController toQIdx:[treeController selectedNodes][0]]; - - // ask the tree controller for the current selection - if (auto selected = RecentModel::instance().getActiveCall(RecentModel::instance().peopleProxy()->mapToSource(qIdx))) { - CallModel::instance().selectCall(selected); - } else if (auto selected = RecentModel::instance().getActiveCall(RecentModel::instance().peopleProxy()->mapToSource(qIdx.parent()))){ - CallModel::instance().selectCall(selected); - } else { - CallModel::instance().selectionModel()->clearCurrentIndex(); - } } /* View Based OutlineView: See the delegate method -tableView:viewForTableColumn:row: in NSTableView. diff --git a/ui/Base.lproj/Broker.strings b/ui/Base.lproj/Broker.strings new file mode 100644 index 00000000..1822dc74 --- /dev/null +++ b/ui/Base.lproj/Broker.strings @@ -0,0 +1,12 @@ + +/* Class = "NSTextFieldCell"; title = "Display Role"; ObjectID = "1Rl-Yq-z7r"; */ +"1Rl-Yq-z7r.title" = "Display Role"; + +/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "3lU-Go-v0h"; */ +"3lU-Go-v0h.title" = "Text Cell"; + +/* Class = "NSSearchFieldCell"; placeholderString = "Search or enter number"; ObjectID = "5vh-ub-Dsq"; */ +"5vh-ub-Dsq.placeholderString" = "Search or enter number"; + +/* Class = "NSTextFieldCell"; title = "details"; ObjectID = "sQW-4V-hwv"; */ +"sQW-4V-hwv.title" = "details"; diff --git a/ui/Base.lproj/CurrentCall.strings b/ui/Base.lproj/CurrentCall.strings index b5c3790a..a94e1e91 100644 --- a/ui/Base.lproj/CurrentCall.strings +++ b/ui/Base.lproj/CurrentCall.strings @@ -1,28 +1,49 @@ +/* Class = "NSButton"; ibShadowedToolTip = "Join call"; ObjectID = "9e8-ji-QId"; */ +"9e8-ji-QId.ibShadowedToolTip" = "Join call"; + +/* Class = "NSButton"; ibShadowedToolTip = "Transfer"; ObjectID = "ChW-kg-Sja"; */ +"ChW-kg-Sja.ibShadowedToolTip" = "Transfer"; + /* Class = "NSTextFieldCell"; title = "URI"; ObjectID = "Dqv-um-UUk"; */ "Dqv-um-UUk.title" = "URI"; -/* Class = "NSTextFieldCell"; title = "details"; ObjectID = "FHf-0w-WGz"; */ -"FHf-0w-WGz.title" = "details"; +/* Class = "NSButtonCell"; title = "Answer"; ObjectID = "KPG-pB-gPm"; */ +"KPG-pB-gPm.title" = "Answer"; -/* Class = "NSTextFieldCell"; title = "Display Role"; ObjectID = "FhU-gw-okq"; */ -"FhU-gw-okq.title" = "Display Role"; +/* Class = "NSButton"; ibShadowedToolTip = "Hang up"; ObjectID = "Kjq-iM-NBL"; */ +"Kjq-iM-NBL.ibShadowedToolTip" = "Hang up"; -/* Class = "NSSearchFieldCell"; placeholderString = "Search or enter number"; ObjectID = "GeP-AW-8mu"; */ -"GeP-AW-8mu.placeholderString" = "Search or enter number"; +/* Class = "NSButton"; ibShadowedToolTip = "Mute Video"; ObjectID = "LVS-yZ-98V"; */ +"LVS-yZ-98V.ibShadowedToolTip" = "Mute Video"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "GjO-zY-hdp"; */ -"GjO-zY-hdp.title" = "Text Cell"; +/* Class = "NSButton"; ibShadowedToolTip = "Hold"; ObjectID = "anb-Y8-JQi"; */ +"anb-Y8-JQi.ibShadowedToolTip" = "Hold"; -/* Class = "NSButtonCell"; title = "Answer"; ObjectID = "KPG-pB-gPm"; */ -"KPG-pB-gPm.title" = "Answer"; +/* Class = "NSButton"; ibShadowedToolTip = "Toggle chat"; ObjectID = "fmp-x4-Pef"; */ +"fmp-x4-Pef.ibShadowedToolTip" = "Toggle chat"; + +/* Class = "NSButton"; ibShadowedToolTip = "Add participant"; ObjectID = "kIZ-mf-moM"; */ +"kIZ-mf-moM.ibShadowedToolTip" = "Add participant"; /* Class = "NSButtonCell"; title = "Button"; ObjectID = "kxH-yM-TLd"; */ "kxH-yM-TLd.title" = "Button"; +/* Class = "NSButton"; ibShadowedToolTip = "Hang up"; ObjectID = "mc3-HV-hek"; */ +"mc3-HV-hek.ibShadowedToolTip" = "Hang up"; + +/* Class = "NSButton"; ibShadowedToolTip = "Record"; ObjectID = "oRa-pS-HN2"; */ +"oRa-pS-HN2.ibShadowedToolTip" = "Record"; + /* Class = "NSTextFieldCell"; title = "Person name"; ObjectID = "osk-LS-0Qg"; */ "osk-LS-0Qg.title" = "Person name"; +/* Class = "NSButton"; ibShadowedToolTip = "Pick up"; ObjectID = "qgD-3D-nD5"; */ +"qgD-3D-nD5.ibShadowedToolTip" = "Pick up"; + +/* Class = "NSButton"; ibShadowedToolTip = "Mute Audio"; ObjectID = "tQl-cT-0Lb"; */ +"tQl-cT-0Lb.ibShadowedToolTip" = "Mute Audio"; + /* Class = "NSTextFieldCell"; title = "State"; ObjectID = "ugy-uK-901"; */ "ugy-uK-901.title" = "State"; diff --git a/ui/Base.lproj/CurrentCall.xib b/ui/Base.lproj/CurrentCall.xib index 5560aa89..fbae36f9 100644 --- a/ui/Base.lproj/CurrentCall.xib +++ b/ui/Base.lproj/CurrentCall.xib @@ -7,13 +7,16 @@ <customObject id="-2" userLabel="File's Owner" customClass="CurrentCallVC"> <connections> <outlet property="addContactButton" destination="Zss-6A-bSy" id="Px0-5v-NE7"/> + <outlet property="addParticipantButton" destination="kIZ-mf-moM" id="7jn-l5-umS"/> <outlet property="chatButton" destination="fmp-x4-Pef" id="ARt-dr-TRo"/> <outlet property="chatVC" destination="LWe-df-dS6" id="SMR-T0-fYe"/> <outlet property="controlsPanel" destination="Eoi-B8-iL6" id="4xn-3b-SNn"/> <outlet property="hangUpButton" destination="Kjq-iM-NBL" id="Puz-4L-Okl"/> <outlet property="headerContainer" destination="d0X-cW-Xgz" id="7RM-kh-vCm"/> <outlet property="holdOnOffButton" destination="anb-Y8-JQi" id="HSl-pE-Kwg"/> + <outlet property="joinPanel" destination="MNG-eU-B2N" id="oBn-ec-ebh"/> <outlet property="loadingIndicator" destination="JwW-2h-DyZ" id="EEb-50-oSJ"/> + <outlet property="mergeCallsButton" destination="9e8-ji-QId" id="sb6-n5-E7k"/> <outlet property="muteAudioButton" destination="tQl-cT-0Lb" id="qV4-Ef-UTx"/> <outlet property="muteVideoButton" destination="LVS-yZ-98V" id="qQs-zP-wQ4"/> <outlet property="personLabel" destination="bg3-hB-nE8" id="t6l-1B-JxI"/> @@ -120,7 +123,7 @@ <customView translatesAutoresizingMaskIntoConstraints="NO" id="Eoi-B8-iL6" userLabel="Controls"> <rect key="frame" x="20" y="20" width="452" height="67"/> <subviews> - <button horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="tQl-cT-0Lb" userLabel="Mute Audio" customClass="IconButton"> + <button toolTip="Mute Audio" horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="tQl-cT-0Lb" userLabel="Mute Audio" customClass="IconButton"> <rect key="frame" x="158" y="13" width="40" height="40"/> <buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" image="ic_action_mute_audio" imagePosition="overlaps" alignment="center" transparent="YES" imageScaling="proportionallyDown" id="7wg-Q4-mbD"> <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> @@ -141,30 +144,8 @@ <action selector="muteAudio:" target="-2" id="DBk-mG-FLj"/> </connections> </button> - <button horizontalHuggingPriority="750" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="qgD-3D-nD5" userLabel="Accept" customClass="IconButton"> - <rect key="frame" x="8" y="14" width="40" height="40"/> - <constraints> - <constraint firstAttribute="height" constant="40" id="IFG-ni-9mc"/> - <constraint firstAttribute="width" constant="40" id="uoL-Wy-Ek2"/> - </constraints> - <buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" image="ic_action_call" imagePosition="overlaps" alignment="left" transparent="YES" imageScaling="proportionallyDown" id="CoO-HS-nEB"> - <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> - <font key="font" metaFont="system"/> - </buttonCell> - <userDefinedRuntimeAttributes> - <userDefinedRuntimeAttribute type="number" keyPath="imageInsets"> - <integer key="value" value="8"/> - </userDefinedRuntimeAttribute> - <userDefinedRuntimeAttribute type="color" keyPath="bgColor"> - <color key="value" red="0.23529411764705882" green="0.6470588235294118" blue="0.16078431372549018" alpha="0.80000000000000004" colorSpace="calibratedRGB"/> - </userDefinedRuntimeAttribute> - </userDefinedRuntimeAttributes> - <connections> - <action selector="accept:" target="-2" id="maS-G8-eY7"/> - </connections> - </button> - <button horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="oRa-pS-HN2" customClass="IconButton"> - <rect key="frame" x="247" y="13" width="40" height="40"/> + <button toolTip="Record" horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="oRa-pS-HN2" customClass="IconButton"> + <rect key="frame" x="249" y="13" width="40" height="40"/> <buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" image="ic_action_record" imagePosition="overlaps" alignment="center" transparent="YES" imageScaling="proportionallyDown" id="rhz-4Z-avV"> <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> <font key="font" size="10" name=".HelveticaNeueDeskInterface-Regular"/> @@ -184,8 +165,8 @@ <action selector="toggleRecording:" target="-2" id="gAc-ZJ-9PN"/> </connections> </button> - <button wantsLayer="YES" horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="fmp-x4-Pef" userLabel="Chat" customClass="IconButton"> - <rect key="frame" x="392" y="12" width="40" height="40"/> + <button toolTip="Toggle chat" wantsLayer="YES" horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="fmp-x4-Pef" userLabel="Chat" customClass="IconButton"> + <rect key="frame" x="392" y="13" width="40" height="40"/> <backgroundFilters> <ciFilter name="CIColorMonochrome"> <configuration> @@ -214,9 +195,9 @@ <action selector="toggleChat:" target="-2" id="7HN-HS-oqT"/> </connections> </button> - <button horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="LVS-yZ-98V" userLabel="Mute Video" customClass="IconButton"> - <rect key="frame" x="197" y="14" width="40" height="40"/> - <buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" image="ic_action_mute_video" imagePosition="overlaps" alignment="center" transparent="YES" imageScaling="proportionallyDown" id="sSe-V6-C7i"> + <button toolTip="Hold" horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="anb-Y8-JQi" userLabel="Hold" customClass="IconButton"> + <rect key="frame" x="113" y="13" width="40" height="40"/> + <buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" image="ic_action_hold" imagePosition="overlaps" alignment="center" transparent="YES" imageScaling="proportionallyDown" id="7w5-d1-mNe"> <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> <font key="font" metaFont="system"/> </buttonCell> @@ -232,11 +213,53 @@ </userDefinedRuntimeAttribute> </userDefinedRuntimeAttributes> <connections> - <action selector="muteVideo:" target="-2" id="a6W-aB-zWX"/> + <action selector="toggleHold:" target="-2" id="O18-nN-hHE"/> + </connections> + </button> + <button toolTip="Transfer" horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ChW-kg-Sja" customClass="IconButton"> + <rect key="frame" x="294" y="13" width="40" height="40"/> + <buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" image="ic_action_transfer" imagePosition="overlaps" alignment="center" transparent="YES" imageScaling="proportionallyDown" id="FOs-Wt-c2R"> + <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> + <font key="font" size="10" name=".HelveticaNeueDeskInterface-Regular"/> + </buttonCell> + <userDefinedRuntimeAttributes> + <userDefinedRuntimeAttribute type="number" keyPath="imageInsets"> + <integer key="value" value="8"/> + </userDefinedRuntimeAttribute> + <userDefinedRuntimeAttribute type="color" keyPath="highlightColor"> + <color key="value" red="0.16862745100000001" green="0.70588235290000001" blue="0.78823529410000004" alpha="1" colorSpace="calibratedRGB"/> + </userDefinedRuntimeAttribute> + <userDefinedRuntimeAttribute type="color" keyPath="bgColor"> + <color key="value" red="0.16078431369999999" green="0.16078431369999999" blue="0.16078431369999999" alpha="0.80000000000000004" colorSpace="calibratedRGB"/> + </userDefinedRuntimeAttribute> + </userDefinedRuntimeAttributes> + <connections> + <action selector="toggleTransferView:" target="-2" id="Gxt-lS-qZs"/> + </connections> + </button> + <button toolTip="Add participant" horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="kIZ-mf-moM" customClass="IconButton"> + <rect key="frame" x="342" y="13" width="40" height="40"/> + <buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" image="ic_action_add_participant" imagePosition="overlaps" alignment="center" transparent="YES" imageScaling="proportionallyDown" id="BOx-wf-CM5"> + <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> + <font key="font" size="10" name=".HelveticaNeueDeskInterface-Regular"/> + </buttonCell> + <userDefinedRuntimeAttributes> + <userDefinedRuntimeAttribute type="number" keyPath="imageInsets"> + <integer key="value" value="8"/> + </userDefinedRuntimeAttribute> + <userDefinedRuntimeAttribute type="color" keyPath="highlightColor"> + <color key="value" red="0.16862745100000001" green="0.70588235290000001" blue="0.78823529410000004" alpha="1" colorSpace="calibratedRGB"/> + </userDefinedRuntimeAttribute> + <userDefinedRuntimeAttribute type="color" keyPath="bgColor"> + <color key="value" red="0.16078431369999999" green="0.16078431369999999" blue="0.16078431369999999" alpha="0.80000000000000004" colorSpace="calibratedRGB"/> + </userDefinedRuntimeAttribute> + </userDefinedRuntimeAttributes> + <connections> + <action selector="toggleAddParticipantView:" target="-2" id="v6X-2r-6im"/> </connections> </button> - <button horizontalHuggingPriority="750" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Kjq-iM-NBL" userLabel="Hang Up" customClass="IconButton"> - <rect key="frame" x="58" y="13" width="40" height="40"/> + <button toolTip="Hang up" horizontalHuggingPriority="750" verticalHuggingPriority="750" ambiguous="YES" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Kjq-iM-NBL" userLabel="Hang Up" customClass="IconButton"> + <rect key="frame" x="64" y="13" width="40" height="40"/> <constraints> <constraint firstAttribute="width" constant="40" id="MYx-uE-Bej"/> <constraint firstAttribute="height" constant="40" id="dmD-ga-Kwv"/> @@ -257,9 +280,13 @@ <action selector="hangUp:" target="-2" id="1Fj-b8-nfh"/> </connections> </button> - <button horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="anb-Y8-JQi" userLabel="Hold" customClass="IconButton"> - <rect key="frame" x="119" y="14" width="40" height="40"/> - <buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" image="ic_action_hold" imagePosition="overlaps" alignment="center" transparent="YES" imageScaling="proportionallyDown" id="7w5-d1-mNe"> + <button toolTip="Pick up" horizontalHuggingPriority="750" verticalHuggingPriority="750" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="qgD-3D-nD5" userLabel="Accept" customClass="IconButton"> + <rect key="frame" x="11" y="13" width="40" height="40"/> + <constraints> + <constraint firstAttribute="height" constant="40" id="IFG-ni-9mc"/> + <constraint firstAttribute="width" constant="40" id="uoL-Wy-Ek2"/> + </constraints> + <buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" image="ic_action_call" imagePosition="overlaps" alignment="left" transparent="YES" imageScaling="proportionallyDown" id="CoO-HS-nEB"> <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> <font key="font" metaFont="system"/> </buttonCell> @@ -267,22 +294,19 @@ <userDefinedRuntimeAttribute type="number" keyPath="imageInsets"> <integer key="value" value="8"/> </userDefinedRuntimeAttribute> - <userDefinedRuntimeAttribute type="color" keyPath="highlightColor"> - <color key="value" red="0.16862745100000001" green="0.70588235290000001" blue="0.78823529410000004" alpha="1" colorSpace="calibratedRGB"/> - </userDefinedRuntimeAttribute> <userDefinedRuntimeAttribute type="color" keyPath="bgColor"> - <color key="value" red="0.16078431369999999" green="0.16078431369999999" blue="0.16078431369999999" alpha="0.80000000000000004" colorSpace="calibratedRGB"/> + <color key="value" red="0.23529411764705882" green="0.6470588235294118" blue="0.16078431372549018" alpha="0.80000000000000004" colorSpace="calibratedRGB"/> </userDefinedRuntimeAttribute> </userDefinedRuntimeAttributes> <connections> - <action selector="toggleHold:" target="-2" id="O18-nN-hHE"/> + <action selector="accept:" target="-2" id="maS-G8-eY7"/> </connections> </button> - <button horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ChW-kg-Sja" customClass="IconButton"> - <rect key="frame" x="297" y="12" width="40" height="40"/> - <buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" image="ic_action_transfer" imagePosition="overlaps" alignment="center" transparent="YES" imageScaling="proportionallyDown" id="FOs-Wt-c2R"> + <button toolTip="Mute Video" horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="LVS-yZ-98V" userLabel="Mute Video" customClass="IconButton"> + <rect key="frame" x="204" y="13" width="40" height="40"/> + <buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" image="ic_action_mute_video" imagePosition="overlaps" alignment="center" transparent="YES" imageScaling="proportionallyDown" id="sSe-V6-C7i"> <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> - <font key="font" size="10" name=".HelveticaNeueDeskInterface-Regular"/> + <font key="font" metaFont="system"/> </buttonCell> <userDefinedRuntimeAttributes> <userDefinedRuntimeAttribute type="number" keyPath="imageInsets"> @@ -296,16 +320,14 @@ </userDefinedRuntimeAttribute> </userDefinedRuntimeAttributes> <connections> - <action selector="toggleTransferView:" target="-2" id="Gxt-lS-qZs"/> + <action selector="muteVideo:" target="-2" id="a6W-aB-zWX"/> </connections> </button> </subviews> <constraints> <constraint firstItem="qgD-3D-nD5" firstAttribute="centerY" secondItem="Eoi-B8-iL6" secondAttribute="centerY" id="9NT-bT-9wJ"/> - <constraint firstItem="Kjq-iM-NBL" firstAttribute="centerY" secondItem="Eoi-B8-iL6" secondAttribute="centerY" id="FrX-Hd-30D"/> <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="385" id="TSJ-9A-brf"/> <constraint firstItem="qgD-3D-nD5" firstAttribute="leading" secondItem="Eoi-B8-iL6" secondAttribute="leading" constant="8" id="hhR-YV-cu5"/> - <constraint firstItem="Kjq-iM-NBL" firstAttribute="leading" secondItem="qgD-3D-nD5" secondAttribute="trailing" constant="10" id="j0v-YO-8kM"/> <constraint firstAttribute="height" constant="67" id="ynu-O5-MN8"/> </constraints> </customView> @@ -323,11 +345,67 @@ <constraint firstAttribute="width" constant="175" id="aEv-Tt-tSD"/> </constraints> </customView> + <customView hidden="YES" ambiguous="YES" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="MNG-eU-B2N"> + <rect key="frame" x="258" y="95" width="158" height="66"/> + <subviews> + <button toolTip="Join call" horizontalHuggingPriority="750" verticalHuggingPriority="750" ambiguous="YES" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="9e8-ji-QId" userLabel="Mute Video" customClass="IconButton"> + <rect key="frame" x="98" y="13" width="40" height="40"/> + <constraints> + <constraint firstAttribute="height" constant="40" id="2GQ-Ki-ZmL"/> + <constraint firstAttribute="width" constant="40" id="Ax8-Wg-JeP"/> + </constraints> + <buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" image="ic_action_merge_calls" imagePosition="overlaps" alignment="center" transparent="YES" imageScaling="proportionallyDown" id="7n2-FO-gcG"> + <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> + <font key="font" metaFont="system"/> + </buttonCell> + <userDefinedRuntimeAttributes> + <userDefinedRuntimeAttribute type="number" keyPath="imageInsets"> + <integer key="value" value="8"/> + </userDefinedRuntimeAttribute> + <userDefinedRuntimeAttribute type="color" keyPath="highlightColor"> + <color key="value" red="0.16862745100000001" green="0.70588235290000001" blue="0.78823529410000004" alpha="1" colorSpace="calibratedRGB"/> + </userDefinedRuntimeAttribute> + <userDefinedRuntimeAttribute type="color" keyPath="bgColor"> + <color key="value" red="0.16078431369999999" green="0.16078431369999999" blue="0.16078431369999999" alpha="0.80000000000000004" colorSpace="calibratedRGB"/> + </userDefinedRuntimeAttribute> + </userDefinedRuntimeAttributes> + <connections> + <action selector="mergeCalls:" target="-2" id="GTH-sR-hNd"/> + </connections> + </button> + <button toolTip="Hang up" horizontalHuggingPriority="750" verticalHuggingPriority="750" ambiguous="YES" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="mc3-HV-hek" userLabel="Hang Up" customClass="IconButton"> + <rect key="frame" x="20" y="13" width="40" height="40"/> + <constraints> + <constraint firstAttribute="width" constant="40" id="O83-pI-Vas"/> + <constraint firstAttribute="height" constant="40" id="tQE-0z-Q3y"/> + </constraints> + <buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" image="ic_action_hangup" imagePosition="overlaps" alignment="center" transparent="YES" imageScaling="proportionallyDown" id="qBC-R5-W49"> + <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> + <font key="font" metaFont="system"/> + </buttonCell> + <userDefinedRuntimeAttributes> + <userDefinedRuntimeAttribute type="color" keyPath="bgColor"> + <color key="value" red="0.94509803920000002" green="0.16078431369999999" blue="0.0" alpha="0.83999999999999997" colorSpace="calibratedRGB"/> + </userDefinedRuntimeAttribute> + <userDefinedRuntimeAttribute type="number" keyPath="imageInsets"> + <integer key="value" value="8"/> + </userDefinedRuntimeAttribute> + </userDefinedRuntimeAttributes> + <connections> + <action selector="hangUp:" target="-2" id="MMl-em-Nrb"/> + </connections> + </button> + </subviews> + <constraints> + <constraint firstItem="mc3-HV-hek" firstAttribute="centerY" secondItem="MNG-eU-B2N" secondAttribute="centerY" id="m7g-Q2-BpP"/> + </constraints> + </customView> </subviews> <constraints> <constraint firstAttribute="centerX" secondItem="JwW-2h-DyZ" secondAttribute="centerX" id="4eh-az-oI5"/> <constraint firstItem="6y6-RH-qOp" firstAttribute="leading" secondItem="Eoi-B8-iL6" secondAttribute="trailing" constant="8" id="7wV-uh-Xb7"/> <constraint firstAttribute="bottom" secondItem="Eoi-B8-iL6" secondAttribute="bottom" constant="20" id="9j2-HZ-hNX"/> + <constraint firstItem="MNG-eU-B2N" firstAttribute="centerX" secondItem="2wf-Py-l6B" secondAttribute="centerX" id="DbU-cn-glx"/> <constraint firstAttribute="trailing" secondItem="d0X-cW-Xgz" secondAttribute="trailing" constant="20" id="G79-Jv-EYw"/> <constraint firstAttribute="bottom" secondItem="6y6-RH-qOp" secondAttribute="bottom" constant="20" id="HOt-7O-FU2"/> <constraint firstAttribute="trailing" secondItem="6y6-RH-qOp" secondAttribute="trailing" constant="20" id="KTx-SN-RUg"/> @@ -335,6 +413,7 @@ <constraint firstAttribute="centerY" secondItem="JwW-2h-DyZ" secondAttribute="centerY" id="Na1-o4-4Ds"/> <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="675" id="ciq-ed-2FK"/> <constraint firstItem="d0X-cW-Xgz" firstAttribute="leading" secondItem="2wf-Py-l6B" secondAttribute="leading" constant="20" id="efy-70-qsJ"/> + <constraint firstItem="Eoi-B8-iL6" firstAttribute="top" secondItem="MNG-eU-B2N" secondAttribute="bottom" constant="8" id="jm6-9s-ojD"/> <constraint firstItem="Eoi-B8-iL6" firstAttribute="leading" secondItem="2wf-Py-l6B" secondAttribute="leading" constant="20" id="sHw-xg-QAo"/> </constraints> </customView> @@ -486,10 +565,12 @@ <resources> <image name="NSGoRightTemplate" width="9" height="12"/> <image name="NSUser" width="32" height="32"/> + <image name="ic_action_add_participant" width="72" height="72"/> <image name="ic_action_call" width="72" height="72"/> <image name="ic_action_chat" width="72" height="72"/> <image name="ic_action_hangup" width="72" height="72"/> <image name="ic_action_hold" width="72" height="72"/> + <image name="ic_action_merge_calls" width="72" height="72"/> <image name="ic_action_mute_audio" width="72" height="72"/> <image name="ic_action_mute_video" width="72" height="72"/> <image name="ic_action_record" width="54" height="54"/> -- GitLab