conversations: user search

Change-Id: Icb5c130e8fa2fe7d2691ae7e9b1abaacb78e8bbc
diff --git a/src/AppDelegate.mm b/src/AppDelegate.mm
index 71bbf57..6039dd9 100644
--- a/src/AppDelegate.mm
+++ b/src/AppDelegate.mm
@@ -152,110 +152,114 @@
     QObject::connect(&lrc->getBehaviorController(),
                      &lrc::api::BehaviorController::newTrustRequest,
                      [self] (const QString& accountId, const QString& contactUri) {
-                         BOOL shouldNotify = [[NSUserDefaults standardUserDefaults] boolForKey:Preferences::ContactRequestNotifications];
-                         if(!shouldNotify) {
-                             return;
-                         }
-                         NSUserNotification* notification = [[NSUserNotification alloc] init];
-                         auto contactModel = lrc->getAccountModel()
-                         .getAccountInfo(accountId).contactModel.get();
-                         NSString* name = contactModel->getContact(contactUri)
-                         .registeredName.isEmpty() ?
-                         contactUri.toNSString():
-                         contactModel->getContact(contactUri).registeredName.toNSString();
-                         NSString* localizedMessage =
-                         NSLocalizedString(@"Send you a contact request",
-                                           @"Notification message");
+        BOOL shouldNotify = [[NSUserDefaults standardUserDefaults] boolForKey:Preferences::ContactRequestNotifications];
+        if(!shouldNotify) {
+            return;
+        }
+        NSUserNotification* notification = [[NSUserNotification alloc] init];
+        auto contactModel = lrc->getAccountModel()
+        .getAccountInfo(accountId).contactModel.get();
+        NSString* name = contactModel->getContact(contactUri)
+        .registeredName.isEmpty() ?
+        contactUri.toNSString():
+        contactModel->getContact(contactUri).registeredName.toNSString();
+        NSString* localizedMessage =
+        NSLocalizedString(@"Send you a contact request",
+                          @"Notification message");
 
-                         NSMutableDictionary *userInfo = [[NSMutableDictionary alloc] init];
-                         userInfo[ACCOUNT_ID] = accountId.toNSString();
-                         userInfo[CONTACT_URI] = contactUri.toNSString();
-                         userInfo[NOTIFICATION_TYPE] = CONTACT_REQUEST_NOTIFICATION;
+        NSMutableDictionary *userInfo = [[NSMutableDictionary alloc] init];
+        userInfo[ACCOUNT_ID] = accountId.toNSString();
+        userInfo[CONTACT_URI] = contactUri.toNSString();
+        userInfo[NOTIFICATION_TYPE] = CONTACT_REQUEST_NOTIFICATION;
 
-                         [notification setTitle: name];
-                         notification.informativeText = localizedMessage;
-                         [notification setSoundName:NSUserNotificationDefaultSoundName];
-                         [notification setUserInfo: userInfo];
+        [notification setTitle: name];
+        notification.informativeText = localizedMessage;
+        [notification setSoundName:NSUserNotificationDefaultSoundName];
+        [notification setUserInfo: userInfo];
 
-                         [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification];
+        [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification];
 
-                     });
+    });
 
     QObject::connect(&lrc->getBehaviorController(),
                      &lrc::api::BehaviorController::showIncomingCallView,
                      [self] (const QString& accountId, lrc::api::conversation::Info conversationInfo) {
-                         BOOL shouldNotify = [[NSUserDefaults standardUserDefaults] boolForKey:Preferences::CallNotifications];
-                         if(!shouldNotify) {
-                             return;
-                         }
-                         bool isIncoming = false;
-                         auto callModel = lrc->getAccountModel()
-                         .getAccountInfo(accountId).callModel.get();
-                         if(callModel->hasCall(conversationInfo.callId)) {
-                             isIncoming = !callModel->getCall(conversationInfo.callId).isOutgoing;
-                         }
-                         if(!isIncoming) {
-                             return;
-                         }
-                         NSString* name = bestIDForConversation(conversationInfo, *lrc->getAccountModel().getAccountInfo(accountId).conversationModel.get());
-                         NSUserNotification* notification = [[NSUserNotification alloc] init];
+        BOOL shouldNotify = [[NSUserDefaults standardUserDefaults] boolForKey:Preferences::CallNotifications];
+        if(!shouldNotify) {
+            return;
+        }
+        bool isIncoming = false;
+        auto callModel = lrc->getAccountModel()
+        .getAccountInfo(accountId).callModel.get();
+        if(callModel->hasCall(conversationInfo.callId)) {
+            isIncoming = !callModel->getCall(conversationInfo.callId).isOutgoing;
+        }
+        if(!isIncoming) {
+            return;
+        }
+        NSString* name = bestIDForConversation(conversationInfo, *lrc->getAccountModel().getAccountInfo(accountId).conversationModel.get());
+        NSUserNotification* notification = [[NSUserNotification alloc] init];
 
-                         NSMutableDictionary *userInfo = [[NSMutableDictionary alloc] init];
-                         userInfo[ACCOUNT_ID] = accountId.toNSString();
-                         userInfo[CALL_ID] = conversationInfo.callId.toNSString();
-                         userInfo[CONVERSATION_ID] = conversationInfo.uid.toNSString();
-                         userInfo[NOTIFICATION_TYPE] = CALL_NOTIFICATION;
+        NSMutableDictionary *userInfo = [[NSMutableDictionary alloc] init];
+        userInfo[ACCOUNT_ID] = accountId.toNSString();
+        userInfo[CALL_ID] = conversationInfo.callId.toNSString();
+        userInfo[CONVERSATION_ID] = conversationInfo.uid.toNSString();
+        userInfo[NOTIFICATION_TYPE] = CALL_NOTIFICATION;
 
-                         NSString* localizedTitle = [NSString stringWithFormat:
-                                                     NSLocalizedString(@"Incoming call from %@", @"Incoming call from {Name}"),
-                                                     name];
-                         // try to activate action button
-                         @try {
-                             [notification setValue:@YES forKey:@"_showsButtons"];
-                         }
-                         @catch (NSException *exception) {
-                             NSLog(@"Action button not activable on notification");
-                         }
-                         [notification setUserInfo: userInfo];
-                         [notification setOtherButtonTitle:NSLocalizedString(@"Refuse", @"Button Action")];
-                         [notification setActionButtonTitle:NSLocalizedString(@"Accept", @"Button Action")];
-                         [notification setTitle:localizedTitle];
-                         [notification setSoundName:NSUserNotificationDefaultSoundName];
+        NSString* localizedTitle = [NSString stringWithFormat:
+                                    NSLocalizedString(@"Incoming call from %@", @"Incoming call from {Name}"),
+                                    name];
+        // try to activate action button
+        @try {
+            [notification setValue:@YES forKey:@"_showsButtons"];
+        }
+        @catch (NSException *exception) {
+            NSLog(@"Action button not activable on notification");
+        }
+        [notification setUserInfo: userInfo];
+        [notification setOtherButtonTitle:NSLocalizedString(@"Refuse", @"Button Action")];
+        [notification setActionButtonTitle:NSLocalizedString(@"Accept", @"Button Action")];
+        [notification setTitle:localizedTitle];
+        [notification setSoundName:NSUserNotificationDefaultSoundName];
 
-                         [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification];
-                     });
+        [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification];
+    });
 
     QObject::connect(&lrc->getBehaviorController(),
                      &lrc::api::BehaviorController::newUnreadInteraction,
                      [self] (const QString& accountId, const QString& conversation,
                              uint64_t interactionId, const lrc::api::interaction::Info& interaction) {
-                         BOOL shouldNotify = [[NSUserDefaults standardUserDefaults] boolForKey:Preferences::MessagesNotifications];
-                         if(!shouldNotify) {
-                             return;
-                         }
-                         NSUserNotification* notification = [[NSUserNotification alloc] init];
+        BOOL shouldNotify = [[NSUserDefaults standardUserDefaults] boolForKey:Preferences::MessagesNotifications];
+        if(!shouldNotify) {
+            return;
+        }
+        NSUserNotification* notification = [[NSUserNotification alloc] init];
 
-                         NSMutableDictionary *userInfo = [[NSMutableDictionary alloc] init];
-                         userInfo[ACCOUNT_ID] = accountId.toNSString();
-                         userInfo[CONVERSATION_ID] = conversation.toNSString();
-                         userInfo[NOTIFICATION_TYPE] = MESSAGE_NOTIFICATION;
-                         NSString* name = interaction.authorUri.toNSString();
-                         auto convIt = getConversationFromUid(conversation, *lrc->getAccountModel().getAccountInfo(accountId).conversationModel.get());
-                         auto convQueue = lrc->getAccountModel().getAccountInfo(accountId).conversationModel.get()->allFilteredConversations();
-                         if (convIt != convQueue.end()) {
-                             name = bestIDForConversation(*convIt, *lrc->getAccountModel().getAccountInfo(accountId).conversationModel.get());
-                         }
-                         NSString* localizedTitle = [NSString stringWithFormat:
-                                                     NSLocalizedString(@"Incoming message from %@",@"Incoming message from {Name}"),
-                                                     name];
+        NSMutableDictionary *userInfo = [[NSMutableDictionary alloc] init];
+        userInfo[ACCOUNT_ID] = accountId.toNSString();
+        userInfo[CONVERSATION_ID] = conversation.toNSString();
+        userInfo[NOTIFICATION_TYPE] = MESSAGE_NOTIFICATION;
+        NSString* name = interaction.authorUri.toNSString();
+        auto convIt = getConversationFromUid(conversation, *lrc->getAccountModel()
+                                             .getAccountInfo(accountId)
+                                             .conversationModel.get(), false);
+        auto convQueue = lrc->getAccountModel()
+        .getAccountInfo(accountId)
+        .conversationModel.get()->allFilteredConversations();
+        if (convIt != convQueue.end()) {
+            name = bestIDForConversation(*convIt, *lrc->getAccountModel().getAccountInfo(accountId).conversationModel.get());
+        }
+        NSString* localizedTitle = [NSString stringWithFormat:
+                                    NSLocalizedString(@"Incoming message from %@",@"Incoming message from {Name}"),
+                                    name];
 
-                         [notification setTitle:localizedTitle];
-                         [notification setSoundName:NSUserNotificationDefaultSoundName];
-                         [notification setSubtitle:interaction.body.toNSString()];
-                         [notification setUserInfo:userInfo];
+        [notification setTitle:localizedTitle];
+        [notification setSoundName:NSUserNotificationDefaultSoundName];
+        [notification setSubtitle:interaction.body.toNSString()];
+        [notification setUserInfo:userInfo];
 
-                         [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification];
-                     });
+        [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification];
+    });
 }
 
 - (void)userNotificationCenter:(NSUserNotificationCenter *)center didDismissAlert:(NSUserNotification *)alert {
diff --git a/src/ChooseContactVC.mm b/src/ChooseContactVC.mm
index 5340025..58fe50e 100644
--- a/src/ChooseContactVC.mm
+++ b/src/ChooseContactVC.mm
@@ -151,7 +151,7 @@
     auto accountID = conversation.accountId;
     auto convID = conversation.convId;
     auto convMod = convModel->owner.accountModel->getAccountInfo(accountID).conversationModel.get();
-    auto conversationInfo = getConversationFromUid(convID, *convMod);
+    auto conversationInfo = getConversationFromUid(convID, *convMod, false);
     auto convQueue = convModel->owner.accountModel->getAccountInfo(accountID).conversationModel.get()->allFilteredConversations();
     if (conversationInfo == convQueue.end()) {
         return;
@@ -212,7 +212,7 @@
             auto accountID = conversation.accountId;
             auto convID = conversation.convId;
             auto *convMod = convModel->owner.accountModel->getAccountInfo(accountID).conversationModel.get();
-            auto *conversationInfo = &(*getConversationFromUid(convID, *convMod));
+            auto *conversationInfo = &(*getConversationFromUid(convID, *convMod, false));
             if (displayNameString.length > 0) {
                 displayNameString = [displayNameString stringByAppendingString:@", "];
             }
@@ -232,7 +232,7 @@
     auto accountID = conversation.accountId;
     auto convID = conversation.convId;
     auto *convMod = convModel->owner.accountModel->getAccountInfo(accountID).conversationModel.get();
-    auto *conversationInfo = &(*getConversationFromUid(convID, *convMod));
+    auto *conversationInfo = &(*getConversationFromUid(convID, *convMod, false));
     if (conversationInfo->participants.empty()) {
         return nil;
     }
diff --git a/src/ConversationVC.mm b/src/ConversationVC.mm
index 5de8e15..186a8b6 100644
--- a/src/ConversationVC.mm
+++ b/src/ConversationVC.mm
@@ -113,11 +113,8 @@
     if (cachedConv_ != nil)
         return cachedConv_;
 
-    auto convQueue = convModel_->allFilteredConversations();
-
-    auto it = getConversationFromUid(convUid_, *convModel_);
-
-    if (it != convQueue.end())
+    auto it = getConversationFromUid(convUid_, *convModel_, true);
+    if (conversationExists(it, *convModel_, true))
         cachedConv_ = &(*it);
 
     return cachedConv_;
@@ -170,7 +167,13 @@
         return;
 
     // Setup UI elements according to new conversation
+    NSLog(@"account info, %@", conv->accountId.toNSString());
+    NSLog(@"conv info, %@", conv->uid.toNSString());
+    NSLog(@"paricipant info, %@", conv->participants[0].toNSString());
     NSString* bestName = bestNameForConversation(*conv, *convModel_);
+    NSLog(@"account info, %@", conv->accountId.toNSString());
+    NSLog(@"conv info, %@", conv->uid.toNSString());
+    NSLog(@"paricipant info, %@", conv->participants[0].toNSString());
     NSString* bestId = bestIDForConversation(*conv, *convModel_);
     [conversationTitle setStringValue: bestName];
     [conversationID setStringValue: bestId];
diff --git a/src/CurrentCallVC.mm b/src/CurrentCallVC.mm
index 1316ea8..30428d3 100644
--- a/src/CurrentCallVC.mm
+++ b/src/CurrentCallVC.mm
@@ -159,7 +159,10 @@
     callUid_ = callUid;
     convUid_ = convUid;
     accountInfo_ = account;
-    auto convIt = getConversationFromUid(convUid_, *accountInfo_->conversationModel);
+    auto convIt = getConversationFromUid(convUid_, *accountInfo_->conversationModel, true);
+    if (!conversationExists(convIt, *accountInfo_->conversationModel.get(), true)) {
+        return;
+    }
     confUid_ = convIt->confId;
     [self.chatVC setConversationUid:convUid model:account->conversationModel.get()];
     [self connectSignals];
@@ -197,7 +200,7 @@
     QObject::connect(accountInfo_->contactModel.get(),
                      &lrc::api::ContactModel::contactAdded,
                      [self](const QString &contactUri) {
-                         auto convIt = getConversationFromUid(convUid_, *accountInfo_->conversationModel.get());
+                         auto convIt = getConversationFromUid(convUid_, *accountInfo_->conversationModel.get(), false);
                          if (convIt == accountInfo_->conversationModel->allFilteredConversations().end()) {
                              return;
                          }
@@ -317,8 +320,8 @@
 
     auto currentCall = callModel->getCall(callUid_);
     NSLog(@"\n status %@ \n",lrc::api::call::to_string(currentCall.status).toNSString());
-    auto convIt = getConversationFromUid(convUid_, *accountInfo_->conversationModel);
-    if (convIt != accountInfo_->conversationModel->allFilteredConversations().end()) {
+    auto convIt = getConversationFromUid(convUid_, *accountInfo_->conversationModel, true);
+    if (conversationExists(convIt, *accountInfo_->conversationModel, true)) {
         NSString* bestName = bestNameForConversation(*convIt, *accountInfo_->conversationModel);
         [contactNameLabel setStringValue:bestName];
         NSString* ringID = bestIDForConversation(*convIt, *accountInfo_->conversationModel);
@@ -456,8 +459,6 @@
 }
 
 -(void) setBackground {
-    auto* convModel = accountInfo_->conversationModel.get();
-    auto it = getConversationFromUid(convUid_, *convModel);
     NSImage *image= [self getContactImageOfSize:120.0 withDefaultAvatar:NO];
     if(image) {
         CIImage * ciImage = [[CIImage alloc] initWithData:[image TIFFRepresentation]];
@@ -490,7 +491,7 @@
 
 -(NSImage *) getContactImageOfSize: (double) size withDefaultAvatar:(BOOL) shouldDrawDefault {
     auto* convModel = accountInfo_->conversationModel.get();
-    auto convIt = getConversationFromUid(convUid_, *convModel);
+    auto convIt = getConversationFromUid(convUid_, *convModel, false);
     if (convIt == convModel->allFilteredConversations().end()) {
         return nil;
     }
@@ -817,8 +818,12 @@
         return;
 
     // If we accept a conversation with a non trusted contact, we first accept it
-    auto convIt = getConversationFromUid(convUid_, *accountInfo_->conversationModel.get());
-    if (convIt != accountInfo_->conversationModel->allFilteredConversations().end()) {
+    auto convIt = getConversationFromUid(convUid_, *accountInfo_->conversationModel.get(), true);
+    if (!conversationExists(convIt,*accountInfo_->conversationModel.get(), true)) {
+        return;
+    }
+
+    if (convIt == accountInfo_->conversationModel->allFilteredConversations().end()) {
         auto& contact = accountInfo_->contactModel->getContact(convIt->participants[0]);
         if (contact.profileInfo.type == lrc::api::profile::Type::PENDING)
             accountInfo_->conversationModel->makePermanent(convUid_);
diff --git a/src/LeaveMessageVC.mm b/src/LeaveMessageVC.mm
index fbe8333..a7fac23 100644
--- a/src/LeaveMessageVC.mm
+++ b/src/LeaveMessageVC.mm
@@ -189,7 +189,7 @@
 }
 
 -(void) updateView {
-    auto it = getConversationFromUid(conversationUid, *conversationModel);
+    auto it = getConversationFromUid(conversationUid, *conversationModel, false);
     if (it != conversationModel->allFilteredConversations().end()) {
         auto& imgManip = reinterpret_cast<Interfaces::ImageManipulationDelegate&>(GlobalInstances::pixmapManipulator());
         QVariant photo = imgManip.conversationPhoto(*it, conversationModel->owner, QSize(120, 120), NO);
diff --git a/src/MessagesVC.mm b/src/MessagesVC.mm
index b6cd857..9258027 100644
--- a/src/MessagesVC.mm
+++ b/src/MessagesVC.mm
@@ -177,9 +177,8 @@
 
     if (cachedConv_ != nil)
         return cachedConv_;
-
-    auto it = getConversationFromUid(convUid_, *convModel_);
-    if (it != convModel_->allFilteredConversations().end())
+    auto it = getConversationFromUid(convUid_, *convModel_, true);
+    if (conversationExists(it, *convModel_, true))
         cachedConv_ = &(*it);
 
     return cachedConv_;
diff --git a/src/RingWindowController.mm b/src/RingWindowController.mm
index df2199d..45d82b2 100644
--- a/src/RingWindowController.mm
+++ b/src/RingWindowController.mm
@@ -609,9 +609,8 @@
     [smartViewVC setConversationModel:accInfo.conversationModel.get()];
     [smartViewVC selectConversationList];
     [self updateRingID];
-    auto convInfo = getConversationFromUid(QString::fromNSString(conversationId), *accInfo.conversationModel.get());
-    auto convQueue = accInfo.conversationModel.get()->allFilteredConversations();
-    if (convInfo != convQueue.end()) {
+    auto convInfo = getConversationFromUid(QString::fromNSString(conversationId), *accInfo.conversationModel.get(), true);
+    if (conversationExists(convInfo, *accInfo.conversationModel.get(), true)) {
         [conversationVC setConversationUid:convInfo->uid model:accInfo.conversationModel.get()];
         [smartViewVC selectConversation: *convInfo model:accInfo.conversationModel.get()];
         accInfo.conversationModel.get()->clearUnreadInteractions(QString::fromNSString(conversationId));
@@ -625,9 +624,8 @@
     [settingsVC setSelectedAccount:accInfo.id];
     [smartViewVC setConversationModel:accInfo.conversationModel.get()];
     [self updateRingID];
-    auto convInfo = getConversationFromUid(QString::fromNSString(conversationId), *accInfo.conversationModel.get());
-    auto convQueue = accInfo.conversationModel.get()->allFilteredConversations();
-    if (convInfo != convQueue.end()) {
+    auto convInfo = getConversationFromUid(QString::fromNSString(conversationId), *accInfo.conversationModel.get(), true);
+    if (conversationExists(convInfo, *accInfo.conversationModel.get(), true)) {
         if (accInfo.contactModel->getContact(convInfo->participants[0]).profileInfo.type == lrc::api::profile::Type::PENDING)
             [smartViewVC selectPendingList];
         else
diff --git a/src/SmartViewVC.mm b/src/SmartViewVC.mm
index 1a68a76..e3438bd 100755
--- a/src/SmartViewVC.mm
+++ b/src/SmartViewVC.mm
@@ -51,13 +51,18 @@
 
     //UI elements
     __unsafe_unretained IBOutlet RingTableView* smartView;
+    __unsafe_unretained IBOutlet RingTableView* searchResultsView;
     __unsafe_unretained IBOutlet NSSearchField* searchField;
+    __unsafe_unretained IBOutlet NSTextField* searchStatus;
+    __unsafe_unretained IBOutlet NSBox* contactsHeader;
+    __unsafe_unretained IBOutlet NSBox* searchResultHeader;
     __strong IBOutlet NSSegmentedControl *listTypeSelector;
     __strong IBOutlet NSLayoutConstraint *listTypeSelectorHeight;
     __strong IBOutlet NSLayoutConstraint *listTypeSelectorBottom;
     bool selectorIsPresent;
 
-    QMetaObject::Connection modelSortedConnection_, modelUpdatedConnection_, filterChangedConnection_, newConversationConnection_, conversationRemovedConnection_, newInteractionConnection_, interactionStatusUpdatedConnection_, conversationClearedConnection;
+    QMetaObject::Connection modelSortedConnection_, modelUpdatedConnection_, filterChangedConnection_, newConversationConnection_, conversationRemovedConnection_, newInteractionConnection_, interactionStatusUpdatedConnection_, conversationClearedConnection, searchStatusChangedConnection_,
+    searchResultUpdated_;
 
     lrc::api::ConversationModel* convModel_;
     QString selectedUid_;
@@ -108,6 +113,10 @@
 
     smartView.selectionHighlightStyle = NSTableViewSelectionHighlightStyleNone;
 
+    [searchResultsView setContextMenuDelegate:self];
+    [searchResultsView setShortcutsDelegate:self];
+    [searchResultsView setDoubleAction:@selector(placeCall:)];
+    searchResultsView.selectionHighlightStyle = NSTableViewSelectionHighlightStyleNone;
 }
 
 - (void)placeCall:(id)sender
@@ -117,12 +126,14 @@
         row = [sender clickedRow];
     else if ([smartView selectedRow] != -1)
         row = [smartView selectedRow];
+    else if ([searchResultsView selectedRow] != -1)
+        row = [searchResultsView selectedRow];
     else
         return;
     if (convModel_ == nil)
         return;
 
-    auto conv = convModel_->filteredConversation(row);
+    auto conv = sender == searchResultsView ? convModel_->searchResultForRow(row) : convModel_->filteredConversation(row);
     convModel_->placeCall(conv.uid);
 }
 
@@ -151,8 +162,17 @@
     [totalInvites setIntValue:totalRequests];
 }
 
+-(void) reloadSearchResults
+{
+    [searchResultHeader setHidden: convModel_->getAllSearchResults().size() == 0];
+    [searchResultsView reloadData];
+    [searchResultsView layoutSubtreeIfNeeded];
+}
+
+
 -(void) reloadData
 {
+    [contactsHeader setHidden: convModel_->allFilteredConversations().empty() || searchField.stringValue.length == 0];
     [smartView deselectAll:nil];
     if (convModel_ == nil)
         return;
@@ -183,7 +203,7 @@
     [smartView layoutSubtreeIfNeeded];
 
     if (!selectedUid_.isEmpty() && convModel_ != nil) {
-        auto it = getConversationFromUid(selectedUid_, *convModel_);
+        auto it = getConversationFromUid(selectedUid_, *convModel_, false);
         if (it != convModel_->allFilteredConversations().end()) {
             NSIndexSet* indexSet = [NSIndexSet indexSetWithIndex:(it - convModel_->allFilteredConversations().begin())];
             [smartView selectRowIndexes:indexSet byExtendingSelection:NO];
@@ -199,11 +219,15 @@
         return;
     }
 
-    auto it = getConversationFromUid(QString::fromNSString(uid), *convModel_);
+    auto it = getConversationFromUid(QString::fromNSString(uid), *convModel_, true);
     if (it != convModel_->allFilteredConversations().end()) {
         NSIndexSet* indexSet = [NSIndexSet indexSetWithIndex:(it - convModel_->allFilteredConversations().begin())];
         [smartView reloadDataForRowIndexes:indexSet
                              columnIndexes:[NSIndexSet indexSetWithIndex:0]];
+    } else if (it != convModel_->getAllSearchResults().end()) {
+        NSIndexSet* indexSet = [NSIndexSet indexSetWithIndex:(it - convModel_->getAllSearchResults().begin())];
+        [searchResultsView reloadDataForRowIndexes:indexSet
+                                     columnIndexes:[NSIndexSet indexSetWithIndex:0]];
     }
 }
 
@@ -231,16 +255,30 @@
     QObject::disconnect(conversationClearedConnection);
     QObject::disconnect(interactionStatusUpdatedConnection_);
     QObject::disconnect(newInteractionConnection_);
+    QObject::disconnect(searchStatusChangedConnection_);
+    QObject::disconnect(searchResultUpdated_);
     [self reloadData];
+    [self reloadSearchResults];
+
     if (convModel_ != nil) {
         modelSortedConnection_ = QObject::connect(convModel_, &lrc::api::ConversationModel::modelSorted,
                                                         [self] (){
                                                             [self reloadData];
                                                         });
+        searchStatusChangedConnection_ = QObject::connect(convModel_, &lrc::api::ConversationModel::searchStatusChanged,
+                                                          [self](const QString &status) {
+            [searchStatus setHidden:status.isEmpty()];
+            auto statusString = status.toNSString();
+            [searchStatus setStringValue: statusString];
+                                                          });
         modelUpdatedConnection_ = QObject::connect(convModel_, &lrc::api::ConversationModel::conversationUpdated,
                                                         [self] (const QString& convUid){
                                                             [self reloadConversationWithUid: convUid.toNSString()];
                                                         });
+        searchResultUpdated_ = QObject::connect(convModel_, &lrc::api::ConversationModel::searchResultUpdated,
+                                                               [self] (){
+                                                                   [self reloadSearchResults];
+                                                               });
         filterChangedConnection_ = QObject::connect(convModel_, &lrc::api::ConversationModel::filterChanged,
                                                         [self] (){
                                                             [self reloadData];
@@ -290,11 +328,15 @@
         return;
     }
 
-    auto it = getConversationFromUid(selectedUid_, *convModel_);
+    auto it = getConversationFromUid(uid, *convModel_, true);
     if (it != convModel_->allFilteredConversations().end()) {
         NSIndexSet* indexSet = [NSIndexSet indexSetWithIndex:(it - convModel_->allFilteredConversations().begin())];
         [smartView selectRowIndexes:indexSet byExtendingSelection:NO];
         selectedUid_ = uid;
+    } else if (it != convModel_->getAllSearchResults().end()) {
+        NSIndexSet* indexSet = [NSIndexSet indexSetWithIndex:(it - convModel_->getAllSearchResults().begin())];
+        [searchResultsView selectRowIndexes:indexSet byExtendingSelection:NO];
+        selectedUid_ = uid;
     }
 }
 
@@ -377,19 +419,27 @@
 - (void)tableViewSelectionDidChange:(NSNotification *)notification
 {
     NSInteger row = [notification.object selectedRow];
-    NSInteger rows = [smartView numberOfRows];
+    NSInteger rows = notification.object == smartView ? [smartView numberOfRows] : [searchResultsView numberOfRows];
 
-    for (int i = 0; i< rows; i++) {
-        HoverTableRowView* cellRowView = [smartView rowViewAtRow:i makeIfNecessary: NO];
-        [cellRowView drawSelection: (i == row)];
+    if (notification.object == smartView) {
+
+        for (int i = 0; i< rows; i++) {
+            HoverTableRowView* cellRowView = [smartView rowViewAtRow:i makeIfNecessary: NO];
+            [cellRowView drawSelection: (i == row)];
+        }
+
+    } else {
+        for (int i = 0; i< rows; i++) {
+            HoverTableRowView* cellRowView = [searchResultsView rowViewAtRow:i makeIfNecessary: NO];
+            [cellRowView drawSelection: (i == row)];
+        }
     }
-
     if (row == -1)
         return;
     if (convModel_ == nil)
         return;
 
-    auto uid = convModel_->filteredConversation(row).uid;
+    auto uid = notification.object == smartView ? convModel_->filteredConversation(row).uid : convModel_->searchResultForRow(row).uid;
     if (selectedUid_ != uid) {
         selectedUid_ = uid;
         convModel_->selectConversation(uid);
@@ -408,7 +458,9 @@
     if (convModel_ == nil)
         return nil;
 
-    auto conversation = convModel_->filteredConversation(row);
+    bool isSearching = tableView == searchResultsView;
+
+    auto conversation = isSearching ? convModel_->searchResultForRow(row) : convModel_->filteredConversation(row);
     NSTableCellView* result;
 
     result = [tableView makeViewWithIdentifier:@"MainCell" owner:tableView];
@@ -544,6 +596,7 @@
     }
 
     return result;
+
 }
 
 - (CGFloat)tableView:(NSTableView *)tableView heightOfRow:(NSInteger)row
@@ -556,9 +609,15 @@
 - (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
 {
     if (tableView == smartView && convModel_ != nullptr) {
+        bool hideSmartView = convModel_->getAllSearchResults().size() > 0 && convModel_->allFilteredConversations().size() == 0;
+        [[[smartView superview] superview] setHidden: hideSmartView];
         return convModel_->allFilteredConversations().size();
     }
 
+    if (tableView == searchResultsView && convModel_ != nullptr) {
+        [[[searchResultsView superview] superview] setHidden: convModel_->getAllSearchResults().size() == 0];
+        return convModel_->getAllSearchResults().size();
+    }
     return 0;
 }
 
@@ -623,7 +682,7 @@
     }
     [self clearSearchField];
     auto uid = QString::fromNSString(uId);
-    auto it = getConversationFromUid(uid, *convModel_);
+    auto it = getConversationFromUid(uid, *convModel_, false);
     if (it != convModel_->allFilteredConversations().end()) {
         @try {
             auto contact = convModel_->owner.contactModel->getContact(it->participants[0]);
@@ -660,10 +719,11 @@
         [self displayErrorModalWithTitle:NSLocalizedString(@"No account available", @"Displayed as RingID when no accounts are available for selection") WithMessage:NSLocalizedString(@"Navigate to preferences to create a new account", @"Allert message when no accounts are available")];
         return NO;
     }
-    if (convModel_->allFilteredConversations().size() <= 0) {
+    if (convModel_->getAllSearchResults().size() <= 0 && convModel_->allFilteredConversations().size() <= 0) {
         return YES;
     }
-    auto model = convModel_->filteredConversation(0);
+    bool hasSearchResult = convModel_->getAllSearchResults().size() > 0;
+    auto model = hasSearchResult ? convModel_->searchResultForRow(0) : convModel_->filteredConversation(0);
     auto uid = model.uid;
     if (selectedUid_ == uid) {
         return YES;
@@ -723,12 +783,13 @@
 
 #pragma mark - ContextMenuDelegate
 
-- (NSMenu*) contextualMenuForRow:(int) index
+- (NSMenu*) contextualMenuForRow:(int) index table:(NSTableView*) table
 {
     if (convModel_ == nil)
         return nil;
 
-    auto conversation = convModel_->filteredConversation(NSInteger(index));
+    auto conversation = table == smartView ? convModel_->filteredConversation(NSInteger(index)) :
+    convModel_->searchResultForRow(NSInteger(index));
 
     @try {
         auto contact = convModel_->owner.contactModel->getContact(conversation.participants[0]);
diff --git a/src/utils.h b/src/utils.h
index 196560c..b825344 100755
--- a/src/utils.h
+++ b/src/utils.h
@@ -127,13 +127,33 @@
  * the iterator is invalid thus it needs to be checked by caller.
  * @param uid UID of conversation being searched
  * @param model ConversationModel in which to do the lookup
+ * @param includeSearchResult include search result
  * @return iterator pointing to corresponding Conversation if any. Points to past-the-end element otherwise.
  */
-static inline lrc::api::ConversationModel::ConversationQueue::const_iterator getConversationFromUid(const QString& uid, const lrc::api::ConversationModel& model) {
-    return std::find_if(model.allFilteredConversations().begin(), model.allFilteredConversations().end(),
+static inline lrc::api::ConversationModel::ConversationQueue::const_iterator getConversationFromUid(const QString& uid, const lrc::api::ConversationModel& model, bool includeSearchResult) {
+    auto result = std::find_if(model.allFilteredConversations().begin(), model.allFilteredConversations().end(),
                         [&] (const lrc::api::conversation::Info& conv) {
                             return uid == conv.uid;
                         });
+    if (!includeSearchResult || (result != model.allFilteredConversations().end())) {
+        return result;
+    }
+    return std::find_if(model.getAllSearchResults().begin(), model.getAllSearchResults().end(),
+    [&] (const lrc::api::conversation::Info& conv) {
+        return uid == conv.uid;
+    });
+}
+
+/**
+ * This function true if conversation exists
+ * the iterator is invalid thus it needs to be checked by caller.
+ * @param conversation iterator pointing to a Conversation::Info in ConversationModel
+ * @param model ConversationModel in which to do the lookup
+ * @param includeSearchResult include search result
+ * @return iterator pointing to corresponding Conversation if any. Points to past-the-end element otherwise.
+ */
+static inline bool conversationExists(lrc::api::ConversationModel::ConversationQueue::const_iterator conversation, const lrc::api::ConversationModel& model, bool includeSearchResult) {
+    return includeSearchResult ? (conversation != model.allFilteredConversations().end() || conversation != model.getAllSearchResults().end()) : conversation != model.allFilteredConversations().end();
 }
 
 /**
diff --git a/src/views/RingTableView.h b/src/views/RingTableView.h
index 230337b..300d606 100644
--- a/src/views/RingTableView.h
+++ b/src/views/RingTableView.h
@@ -24,7 +24,7 @@
 
 @required
 
-- (NSMenu*) contextualMenuForRow:(int) index;
+- (NSMenu*) contextualMenuForRow:(int) index table:(NSTableView*) table;
 
 @end
 
diff --git a/src/views/RingTableView.mm b/src/views/RingTableView.mm
index ca1b9af..7bd2e80 100644
--- a/src/views/RingTableView.mm
+++ b/src/views/RingTableView.mm
@@ -29,7 +29,7 @@
     NSPoint pt = [self convertPoint:[evt locationInWindow] fromView:nil];
     int rowIdx = [self rowAtPoint:pt];
     if (self.contextMenuDelegate && rowIdx >= 0) {
-        return [self.contextMenuDelegate contextualMenuForRow:rowIdx];
+        return [self.contextMenuDelegate contextualMenuForRow:rowIdx table: self];
     }
     return nil;
 }