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 &current, 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 &current, 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