call: implement leave message view

Change-Id: Ie4ab6134d39907d108e6a5bf39a863cb56ede684
Reviewed-by: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com>
diff --git a/src/AppDelegate.mm b/src/AppDelegate.mm
index cee3139..134a457 100644
--- a/src/AppDelegate.mm
+++ b/src/AppDelegate.mm
@@ -319,7 +319,7 @@
 - (void) showMainWindow
 {
     if(self.ringWindowController == nil) {
-        self.ringWindowController = [[RingWindowController alloc] initWithWindowNibName:@"RingWindow" bundle: nil accountModel:&lrc->getAccountModel() dataTransferModel:&lrc->getDataTransferModel() behaviourController:&lrc->getBehaviorController()];
+        self.ringWindowController = [[RingWindowController alloc] initWithWindowNibName:@"RingWindow" bundle: nil accountModel:&lrc->getAccountModel() dataTransferModel:&lrc->getDataTransferModel() behaviourController:&lrc->getBehaviorController() avModel: &lrc->getAVModel()];
     }
     [[NSApplication sharedApplication] removeWindowsItem:self.wizard.window];
     [self.ringWindowController.window makeKeyAndOrderFront:self];
diff --git a/src/ConversationVC.h b/src/ConversationVC.h
index c56b100..c6e5860 100644
--- a/src/ConversationVC.h
+++ b/src/ConversationVC.h
@@ -18,12 +18,19 @@
  */
 
 #import <Cocoa/Cocoa.h>
-#import <api/conversation.h>
-#import <api/conversationmodel.h>
+#import <string>
 
+namespace lrc {
+    namespace api {
+        class AVModel;
+        class ConversationModel;
+    }
+}
 @class RingWindowController;
+@class LeaveMessageVC;
+@protocol LeaveMessageDelegate;
 
-@interface ConversationVC : NSViewController
+@interface ConversationVC : NSViewController <LeaveMessageDelegate>
 
 -(void) initFrame;
 -(void) showWithAnimation:(BOOL)animate;
@@ -31,6 +38,9 @@
 
 - (void) setConversationUid:(const std::string)convUid model:(lrc::api::ConversationModel*)model;
 
-- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil delegate:(RingWindowController*) mainWindow;
+- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil delegate:(RingWindowController*) mainWindow aVModel:(lrc::api::AVModel*) avModel;
+- (void) presentLeaveMessageView;
+
+-(NSViewController*) getMessagesView;
 
 @end
diff --git a/src/ConversationVC.mm b/src/ConversationVC.mm
index 9d2fe89..f787e15 100644
--- a/src/ConversationVC.mm
+++ b/src/ConversationVC.mm
@@ -36,8 +36,12 @@
 #import "utils.h"
 #import "RingWindowController.h"
 #import "NSString+Extensions.h"
+#import "LeaveMessageVC.h"
+#import <QuickLook/QuickLook.h>
+#import <Quartz/Quartz.h>
+#import "LeaveMessageVC.h"
 
-@interface ConversationVC () {
+@interface ConversationVC () <QLPreviewPanelDataSource, QLPreviewPanelDelegate>{
 
     __unsafe_unretained IBOutlet NSTextField* conversationTitle;
     __unsafe_unretained IBOutlet NSTextField *conversationID;
@@ -46,6 +50,7 @@
 
     __unsafe_unretained IBOutlet NSButton* sentContactRequestButton;
     IBOutlet MessagesVC* messagesViewVC;
+    LeaveMessageVC* leaveMessageVC;
 
     IBOutlet NSLayoutConstraint *titleCenteredConstraint;
     IBOutlet NSLayoutConstraint* titleTopConstraint;
@@ -55,6 +60,7 @@
     lrc::api::ConversationModel* convModel_;
 
     RingWindowController* delegate;
+    NSMutableArray* leaveMessageConversations;
 
     // All those connections are needed to invalidate cached conversation as pointer
     // may not be referencing the same conversation anymore
@@ -69,15 +75,26 @@
 
 @implementation ConversationVC
 
-- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil delegate:(RingWindowController*) mainWindow
+- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil delegate:(RingWindowController*) mainWindow aVModel:(lrc::api::AVModel*) avModel
 {
     if (self = [self initWithNibName:nibNameOrNil bundle:nibBundleOrNil])
     {
         delegate = mainWindow;
+        leaveMessageVC = [[LeaveMessageVC alloc] initWithNibName:@"LeaveMessageVC" bundle:nil];
+        [[leaveMessageVC view] setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
+        [self.view addSubview:[leaveMessageVC view] positioned:NSWindowAbove relativeTo:nil];
+        [leaveMessageVC initFrame];
+        [leaveMessageVC setAVModel: avModel];
+        leaveMessageConversations = [[NSMutableArray alloc] init];
+        leaveMessageVC.delegate = self;
     }
     return self;
 }
 
+-(NSViewController*) getMessagesView {
+    return messagesViewVC;
+}
+
 -(void) clearData {
     cachedConv_ = nil;
     convUid_ = "";
@@ -120,6 +137,11 @@
 
     if (convUid_.empty() || convModel_ == nil)
         return;
+    if([leaveMessageConversations containsObject:@(convUid_.c_str())]) {
+        [leaveMessageVC setConversationUID: convUid_ conversationModel: convModel_];
+    } else {
+        [leaveMessageVC hide];
+    }
 
     // Signals tracking changes in conversation list, we need them as cached conversation can be invalid
     // after a reordering.
@@ -247,5 +269,13 @@
     [CATransaction commit];
 }
 
+- (void) presentLeaveMessageView {
+    [leaveMessageVC setConversationUID: convUid_ conversationModel: convModel_];
+    [leaveMessageConversations addObject:@(convUid_.c_str())];
+}
+
+-(void) messageCompleted {
+    [leaveMessageConversations removeObject:@(convUid_.c_str())];
+}
 
 @end
diff --git a/src/LeaveMessageVC.h b/src/LeaveMessageVC.h
new file mode 100644
index 0000000..3ef6561
--- /dev/null
+++ b/src/LeaveMessageVC.h
@@ -0,0 +1,45 @@
+/*
+ *  Copyright (C) 2018 Savoir-faire Linux Inc.
+ *  Author: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ */
+#import <Cocoa/Cocoa.h>
+#import <string>
+
+namespace lrc {
+    namespace api {
+        class AVModel;
+        class ConversationModel;
+    }
+}
+
+@protocol LeaveMessageDelegate
+
+-(void) messageCompleted;
+
+@end
+
+@interface LeaveMessageVC : NSViewController
+
+@property (retain, nonatomic) id <LeaveMessageDelegate> delegate;
+
+-(void)setConversationUID:(const std::string) convUid conversationModel:(lrc::api::ConversationModel*) convModel;
+-(void) hide;
+-(void) initFrame;
+-(void) setAVModel: (const lrc::api::AVModel*) avmodel;
+
+@end
+
diff --git a/src/LeaveMessageVC.mm b/src/LeaveMessageVC.mm
new file mode 100644
index 0000000..c35fcfc
--- /dev/null
+++ b/src/LeaveMessageVC.mm
@@ -0,0 +1,203 @@
+/*
+ *  Copyright (C) 2018 Savoir-faire Linux Inc.
+ *  Author: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ */
+
+#import "LeaveMessageVC.h"
+#import "views/NSColor+RingTheme.h"
+#import "utils.h"
+
+//lrc
+#import <api/avmodel.h>
+#import <api/conversationmodel.h>
+
+#import <QuartzCore/QuartzCore.h>
+#import "delegates/ImageManipulationDelegate.h"
+
+//Qt
+#import <QtMacExtras/qmacfunctions.h>
+#import <QPixmap>
+#import <globalinstances.h>
+
+@interface LeaveMessageVC () {
+    __unsafe_unretained IBOutlet NSImageView* personPhoto;
+    __unsafe_unretained IBOutlet NSTextField* infoLabel;
+    __unsafe_unretained IBOutlet NSBox* timerBox;
+    __unsafe_unretained IBOutlet NSTextField* timerLabel;
+    __unsafe_unretained IBOutlet NSBox* sendBox;
+    __unsafe_unretained IBOutlet NSTextField* sendFilename;
+    __unsafe_unretained IBOutlet NSButton* recordButton;
+}
+
+@end
+
+@implementation LeaveMessageVC
+
+bool isRecording = false;
+int recordingTime = 0;
+NSTimer* refreshDurationTimer;
+lrc::api::AVModel* avModel;
+std::string fileName;
+NSMutableDictionary *filesToSend;
+std::string conversationUid;
+lrc::api::ConversationModel* conversationModel;
+
+- (void)loadView {
+    [super loadView];
+    [personPhoto setWantsLayer:YES];
+    personPhoto.layer.masksToBounds =true;
+    personPhoto.layer.cornerRadius = personPhoto.frame.size.width * 0.5;
+    filesToSend = [[NSMutableDictionary alloc] init];
+}
+
+-(void) setAVModel: (lrc::api::AVModel*) avmodel {
+    avModel = avmodel;
+}
+
+-(void) initFrame {
+    [self.view setFrame:self.view.superview.bounds];
+    [self.view setHidden:YES];
+    self.view.layer.position = self.view.frame.origin;
+}
+
+- (IBAction)cancel:(id)sender {
+    [self exit];
+}
+
+- (IBAction)recordMessage:(NSButton *)sender {
+    if (!isRecording) {
+        [self clearData];
+        std::string file_name = avModel->startLocalRecorder(true);
+        if (file_name.empty()) {
+            return;
+        }
+        filesToSend[@(conversationUid.c_str())] = @(file_name.c_str());
+        isRecording = true;
+        recordButton.image = [NSImage imageNamed:@"ic_stoprecord.png"];
+        [timerBox setHidden:NO];
+        if (refreshDurationTimer == nil)
+            refreshDurationTimer = [NSTimer scheduledTimerWithTimeInterval:1.0
+                                                                    target:self
+                                                                  selector:@selector(updateDurationLabel)
+                                                                  userInfo:nil
+                                                                   repeats:YES];
+    } else {
+        avModel->stopLocalRecorder([filesToSend[@(conversationUid.c_str())] UTF8String]);
+        isRecording = false;
+        recordButton.image = [NSImage imageNamed:@"ic_action_audio.png"];
+        [refreshDurationTimer invalidate];
+        refreshDurationTimer = nil;
+        [timerBox setHidden:YES];
+        [sendBox setHidden: NO];
+        [sendFilename setStringValue:[self timeFormatted: recordingTime]];
+    }
+}
+
+- (IBAction)sendMessage:(NSButton *)sender {
+    NSArray* pathURL = [filesToSend[@(conversationUid.c_str())] componentsSeparatedByString: @"/"];
+    if([pathURL count] < 1) {
+        return;
+    }
+    NSString* name = [pathURL objectAtIndex: [pathURL count] - 1];
+    conversationModel->sendFile(conversationUid, [filesToSend[@(conversationUid.c_str())] UTF8String], [name UTF8String]);
+    [filesToSend removeObjectForKey: @(conversationUid.c_str())];
+    [self exit];
+}
+
+- (void) exit {
+    [self clearData];
+    [self hide];
+    [self.delegate messageCompleted];
+}
+
+- (void)clearData {
+    recordButton.image = [NSImage imageNamed:@"ic_action_audio.png"];
+    recordingTime = 0;
+    [timerLabel setStringValue: [self timeFormatted: recordingTime]];
+    isRecording = false;
+    [timerBox setHidden:YES];
+    [sendBox setHidden: YES];
+    [refreshDurationTimer invalidate];
+    refreshDurationTimer = nil;
+    [sendFilename setStringValue:@""];
+    [filesToSend removeObjectForKey: @(conversationUid.c_str())];
+}
+
+- (void)viewWillHide {
+    recordButton.image = [NSImage imageNamed:@"ic_action_audio.png"];
+    if(filesToSend[@(conversationUid.c_str())]) {
+        [sendFilename setStringValue:[self timeFormatted: recordingTime]];
+        [sendBox setHidden: NO];
+    } else {
+        [sendFilename setStringValue:@""];
+        [sendBox setHidden: YES];
+    }
+    recordingTime = 0;
+    [timerLabel setStringValue: [self timeFormatted: recordingTime]];
+    isRecording = false;
+    [timerBox setHidden:YES];
+    [refreshDurationTimer invalidate];
+    refreshDurationTimer = nil;
+}
+
+-(void) hide {
+    if(self.view.frame.origin.x < 0) {
+        return;
+    }
+    [self viewWillHide];
+    [self.view setHidden:YES];
+}
+
+-(void) show {
+    if(self.view.frame.origin.x < 0) {
+        return;
+    }
+    [self.view setHidden:NO];
+}
+
+-(void)setConversationUID:(std::string) convUid conversationModel:(lrc::api::ConversationModel*) convModel {
+    conversationUid = convUid;
+    conversationModel = convModel;
+    [self updateView];
+}
+
+-(void) updateView {
+    auto it = getConversationFromUid(conversationUid, *conversationModel);
+    if (it != conversationModel->allFilteredConversations().end()) {
+        auto& imgManip = reinterpret_cast<Interfaces::ImageManipulationDelegate&>(GlobalInstances::pixmapManipulator());
+        QVariant photo = imgManip.conversationPhoto(*it, conversationModel->owner, QSize(120, 120), NO);
+        [personPhoto setImage:QtMac::toNSImage(qvariant_cast<QPixmap>(photo))];
+        NSString *name = bestNameForConversation(*it, *conversationModel);
+        [infoLabel setStringValue:name];
+    }
+    [self show];
+}
+
+-(void) updateDurationLabel
+{
+    recordingTime++;
+    [timerLabel setStringValue: [self timeFormatted: recordingTime]];
+}
+
+- (NSString *)timeFormatted:(int)totalSeconds
+{
+    int seconds = totalSeconds % 60;
+    int minutes = (totalSeconds / 60) % 60;
+    return [NSString stringWithFormat:@"%02d:%02d",minutes, seconds];
+}
+
+@end
diff --git a/src/LrcModelsProtocol.h b/src/LrcModelsProtocol.h
index f75848e..662f134 100644
--- a/src/LrcModelsProtocol.h
+++ b/src/LrcModelsProtocol.h
@@ -22,6 +22,7 @@
         class DataTransferModel;
         class NewAccountModel;
         class BehaviorController;
+        class AVModel;
     }
 }
 
@@ -30,9 +31,11 @@
 -(id) initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil dataTransferModel:(const lrc::api::DataTransferModel*) dataTransferModel;
 -(id) initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil accountmodel:(const lrc::api::NewAccountModel*) accountModel;
 -(id) initWithWindowNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil accountModel:(const lrc::api::NewAccountModel*)accountModel dataTransferModel:(const lrc::api::DataTransferModel*)dataTransferModel behaviourController:(const lrc::api::BehaviorController*) behaviorController;
+-(id) initWithWindowNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil accountModel:(const lrc::api::NewAccountModel*)accountModel dataTransferModel:(const lrc::api::DataTransferModel*)dataTransferModel behaviourController:(const lrc::api::BehaviorController*) behaviorController avModel: (const lrc::api::AVModel*)avModel;
 
 @property lrc::api::DataTransferModel* dataTransferModel;
 @property lrc::api::NewAccountModel* accountModel;
 @property lrc::api::BehaviorController* behaviorController;
+@property lrc::api::AVModel* avModel;
 
 @end
diff --git a/src/MessagesVC.mm b/src/MessagesVC.mm
index 90360b5..79ebee9 100644
--- a/src/MessagesVC.mm
+++ b/src/MessagesVC.mm
@@ -50,7 +50,6 @@
     std::string convUid_;
     lrc::api::ConversationModel* convModel_;
     const lrc::api::conversation::Info* cachedConv_;
-
     QMetaObject::Connection newInteractionSignal_;
 
     // Both are needed to invalidate cached conversation as pointer
@@ -790,6 +789,24 @@
     return [dateFormatter stringFromDate:msgTime];
 }
 
+- (void) updateSendMessageHeight {
+    NSAttributedString *msgAttString = messageField.attributedStringValue;
+    NSRect frame = NSMakeRect(0, 0, messageField.frame.size.width, msgAttString.size.height);
+    NSTextView *tv = [[NSTextView alloc] initWithFrame:frame];
+    [[tv textStorage] setAttributedString:msgAttString];
+    [tv sizeToFit];
+    CGFloat height = tv.frame.size.height + MEESAGE_MARGIN * 2;
+    CGFloat newHeight = MIN(SEND_PANEL_MAX_HEIGHT, MAX(SEND_PANEL_DEFAULT_HEIGHT, height));
+    if(messagesBottomMargin.constant == newHeight) {
+        return;
+    }
+    messagesBottomMargin.constant = newHeight;
+    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.05 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
+        [self scrollToBottom];
+        sendPanelHeight.constant = newHeight;
+    });
+}
+
 #pragma mark - NSTableViewDataSource
 
 - (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
@@ -877,39 +894,12 @@
     if ([QLPreviewPanel sharedPreviewPanelExists] && [[QLPreviewPanel sharedPreviewPanel] isVisible]) {
         [[QLPreviewPanel sharedPreviewPanel] orderOut:nil];
     } else {
-        [[QLPreviewPanel sharedPreviewPanel] updateController];
-        [QLPreviewPanel sharedPreviewPanel].dataSource = self;
-        [[QLPreviewPanel sharedPreviewPanel] setAnimationBehavior:NSWindowAnimationBehaviorDocumentWindow];
-        [[QLPreviewPanel sharedPreviewPanel] makeKeyAndOrderFront:nil];
+        dispatch_async(dispatch_get_main_queue(), ^{
+            [[QLPreviewPanel sharedPreviewPanel] makeKeyAndOrderFront:self];
+        });
     }
 }
 
-- (NSInteger)numberOfPreviewItemsInPreviewPanel:(QLPreviewPanel *)panel {
-    return 1;
-}
-
-- (id <QLPreviewItem>)previewPanel:(QLPreviewPanel *)panel previewItemAtIndex:(NSInteger)index {
-    return [NSURL fileURLWithPath:previewImage];
-}
-
-- (void) updateSendMessageHeight {
-    NSAttributedString *msgAttString = messageField.attributedStringValue;
-    NSRect frame = NSMakeRect(0, 0, messageField.frame.size.width, msgAttString.size.height);
-    NSTextView *tv = [[NSTextView alloc] initWithFrame:frame];
-    [[tv textStorage] setAttributedString:msgAttString];
-    [tv sizeToFit];
-    CGFloat height = tv.frame.size.height + MEESAGE_MARGIN * 2;
-    CGFloat newHeight = MIN(SEND_PANEL_MAX_HEIGHT, MAX(SEND_PANEL_DEFAULT_HEIGHT, height));
-    if(messagesBottomMargin.constant == newHeight) {
-        return;
-    }
-    messagesBottomMargin.constant = newHeight;
-    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.05 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
-        [self scrollToBottom];
-        sendPanelHeight.constant = newHeight;
-    });
-}
-
 - (IBAction)sendMessage:(id)sender {
     NSString* text = self.message;
     if (text && text.length > 0) {
@@ -971,4 +961,28 @@
     [self updateSendMessageHeight];
 }
 
+#pragma mark - QLPreviewPanelDataSource
+
+-(void)beginPreviewPanelControl:(QLPreviewPanel *)panel
+{
+    panel.dataSource = self;
+}
+
+- (void)endPreviewPanelControl:(QLPreviewPanel *)panel {
+    panel.dataSource = nil;
+}
+
+-(BOOL)acceptsPreviewPanelControl:(QLPreviewPanel *)panel
+{
+    return YES;
+}
+
+- (NSInteger)numberOfPreviewItemsInPreviewPanel:(QLPreviewPanel *)panel {
+    return 1;
+}
+
+- (id <QLPreviewItem>)previewPanel:(QLPreviewPanel *)panel previewItemAtIndex:(NSInteger)index {
+    return [NSURL fileURLWithPath:previewImage];
+}
+
 @end
diff --git a/src/RingWindowController.mm b/src/RingWindowController.mm
index 971622e..dbfd097 100644
--- a/src/RingWindowController.mm
+++ b/src/RingWindowController.mm
@@ -59,6 +59,7 @@
     SHOW_CONVERSATION_SCREEN,
     SHOW_CALL_SCREEN,
     SHOW_SETTINGS_SCREEN,
+    LEAVE_MESSAGE,
 };
 
 @interface RingWindowController () <MigrateRingAccountsDelegate>
@@ -87,24 +88,20 @@
     ConversationVC* conversationVC;
     AccountSettingsVC* settingsVC;
 
-    // toolbar menu items
     IBOutlet ChooseAccountVC* chooseAccountVC;
 }
 
-static NSString* const kPreferencesIdentifier        = @"PreferencesIdentifier";
-NSString* const kChangeAccountToolBarItemIdentifier  = @"ChangeAccountToolBarItemIdentifier";
-NSString* const kOpenAccountToolBarItemIdentifier    = @"OpenAccountToolBarItemIdentifier";
-
-@synthesize dataTransferModel, accountModel, behaviorController;
+@synthesize dataTransferModel, accountModel, behaviorController, avModel;
 @synthesize wizard;
 
--(id) initWithWindowNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil accountModel:( lrc::api::NewAccountModel*)accountModel dataTransferModel:( lrc::api::DataTransferModel*)dataTransferModel behaviourController:( lrc::api::BehaviorController*) behaviorController
+-(id) initWithWindowNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil accountModel:( lrc::api::NewAccountModel*)accountModel dataTransferModel:( lrc::api::DataTransferModel*)dataTransferModel behaviourController:( lrc::api::BehaviorController*) behaviorController avModel: (lrc::api::AVModel*)avModel
 {
     if (self =  [self initWithWindowNibName:nibNameOrNil])
     {
         self.accountModel = accountModel;
         self.dataTransferModel = dataTransferModel;
         self.behaviorController = behaviorController;
+        self.avModel = avModel;
     }
     return self;
 }
@@ -165,6 +162,10 @@
             [smartViewVC.view setHidden: YES];
             [settingsVC show];
             break;
+        case LEAVE_MESSAGE:
+            [conversationVC showWithAnimation: false];
+            [currentCallVC hideWithAnimation: false];
+            [conversationVC presentLeaveMessageView];
         default:
             break;
     }
@@ -178,12 +179,9 @@
 
     currentCallVC = [[CurrentCallVC alloc] initWithNibName:@"CurrentCall" bundle:nil];
     currentCallVC.delegate = self;
-    conversationVC = [[ConversationVC alloc] initWithNibName:@"Conversation" bundle:nil delegate:self];
-    // toolbar items
-    //chooseAccountVC = [[ChooseAccountVC alloc] initWithNibName:@"ChooseAccount" bundle:nil model:self.accountModel delegate:self];
+    conversationVC = [[ConversationVC alloc] initWithNibName:@"Conversation" bundle:nil delegate:self aVModel:self.avModel];
     [chooseAccountVC updateWithDelegate: self andModel:self.accountModel];
     settingsVC = [[AccountSettingsVC alloc] initWithNibName:@"AccountSettings" bundle:nil accountmodel:self.accountModel];
-    //[self.window.contentView addSubview:[chooseAccountVC view]];
     [callView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
     [[currentCallVC view] setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
     [[conversationVC view] setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
@@ -219,6 +217,11 @@
     }
     NSToolbar *tb = [[self window] toolbar];
     [tb setAllowsUserCustomization:NO];
+
+    //add messages view controller to responders chain
+    NSResponder * viewNextResponder = [self nextResponder];
+    [self setNextResponder: [conversationVC getMessagesView]];
+    [[conversationVC getMessagesView] setNextResponder: viewNextResponder];
 }
 
 - (void) connect
@@ -266,6 +269,15 @@
                          [smartViewVC selectConversation: convInfo model:accInfo.conversationModel.get()];
                          [self changeViewTo:SHOW_CONVERSATION_SCREEN];
                      });
+    QObject::connect(self.behaviorController,
+                     &lrc::api::BehaviorController::showLeaveMessageView,
+                     [self](const std::string& accountId,
+                            const lrc::api::conversation::Info& convInfo){
+                         auto& accInfo = self.accountModel->getAccountInfo(accountId);
+                         [conversationVC setConversationUid:convInfo.uid model:accInfo.conversationModel.get()];
+                         [smartViewVC selectConversation: convInfo model:accInfo.conversationModel.get()];
+                         [self changeViewTo:LEAVE_MESSAGE];
+                     });
 }
 
 /**