UI/UX: refactor smartlist

Change-Id: Ibfd5154757908ebd85f4b0060da00a7c608a0e56
Reviewed-by: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com>
diff --git a/src/SmartViewVC.mm b/src/SmartViewVC.mm
index 547cb18..8ee6565 100755
--- a/src/SmartViewVC.mm
+++ b/src/SmartViewVC.mm
@@ -21,6 +21,9 @@
 
 #import "SmartViewVC.h"
 
+//std
+#import <sstream>
+
 //Qt
 #import <QtMacExtras/qmacfunctions.h>
 #import <QPixmap>
@@ -54,11 +57,12 @@
     __unsafe_unretained IBOutlet RingTableView* smartView;
     __unsafe_unretained IBOutlet NSSearchField* searchField;
     __strong IBOutlet NSSegmentedControl *listTypeSelector;
+    __strong IBOutlet NSLayoutConstraint *listTypeSelectorHeight;
     bool selectorIsPresent;
 
-    QMetaObject::Connection modelSortedConnection_, modelUpdatedConnection_, filterChangedConnection_, newConversationConnection_, conversationRemovedConnection_, interactionStatusUpdatedConnection_, conversationClearedConnection;
+    QMetaObject::Connection modelSortedConnection_, modelUpdatedConnection_, filterChangedConnection_, newConversationConnection_, conversationRemovedConnection_, newInteractionConnection_, interactionStatusUpdatedConnection_, conversationClearedConnection;
 
-    lrc::api::ConversationModel* model_;
+    lrc::api::ConversationModel* convModel_;
     std::string selectedUid_;
     lrc::api::profile::Type currentFilterType;
 
@@ -74,12 +78,16 @@
 // Tags for views
 NSInteger const IMAGE_TAG           = 100;
 NSInteger const DISPLAYNAME_TAG     = 200;
-NSInteger const DETAILS_TAG         = 300;
-NSInteger const CALL_BUTTON_TAG     = 400;
-NSInteger const TXT_BUTTON_TAG      = 500;
-NSInteger const CANCEL_BUTTON_TAG   = 600;
-NSInteger const RING_ID_LABEL       = 700;
-NSInteger const PRESENCE_TAG        = 800;
+NSInteger const NOTIFICATONS_TAG    = 300;
+NSInteger const RING_ID_LABEL       = 400;
+NSInteger const PRESENCE_TAG        = 500;
+NSInteger const TOTALMSGS_TAG       = 600;
+NSInteger const TOTALINVITES_TAG    = 700;
+NSInteger const DATE_TAG            = 800;
+NSInteger const SNIPPET_TAG         = 900;
+NSInteger const ADD_BUTTON_TAG            = 1000;
+NSInteger const REFUSE_BUTTON_TAG         = 1100;
+NSInteger const BLOCK_BUTTON_TAG          = 1200;
 
 // Segment indices for smartlist selector
 NSInteger const CONVERSATION_SEG    = 0;
@@ -109,6 +117,9 @@
 
     currentFilterType = lrc::api::profile::Type::RING;
     selectorIsPresent = true;
+
+    smartView.selectionHighlightStyle = NSTableViewSelectionHighlightStyleNone;
+    
 }
 
 - (void)placeCall:(id)sender
@@ -120,57 +131,71 @@
         row = [smartView selectedRow];
     else
         return;
-    if (model_ == nil)
+    if (convModel_ == nil)
         return;
 
-    auto conv = model_->filteredConversation(row);
-    model_->placeCall(conv.uid);
+    auto conv = convModel_->filteredConversation(row);
+    convModel_->placeCall(conv.uid);
+}
+
+-(void) reloadSelectorNotifications
+{
+    NSTextField* totalMsgsCount = [self.view viewWithTag:TOTALMSGS_TAG];
+    NSTextField* totalInvites = [self.view viewWithTag:TOTALINVITES_TAG];
+
+    if (!selectorIsPresent) {
+        [totalMsgsCount setHidden:true];
+        [totalInvites setHidden:true];
+        return;
+    }
+
+    auto ringConversations = convModel_->getFilteredConversations(lrc::api::profile::Type::RING);
+    int totalUnreadMessages = 0;
+    std::for_each(ringConversations.begin(), ringConversations.end(),
+        [&totalUnreadMessages, self] (const auto& conversation) {
+            totalUnreadMessages += convModel_->getNumberOfUnreadMessagesFor(conversation.uid);
+        });
+    [totalMsgsCount setHidden:(totalUnreadMessages == 0)];
+    [totalMsgsCount setIntValue:totalUnreadMessages];
+
+    auto totalRequests = [self chosenAccount].contactModel->pendingRequestCount();
+    [totalInvites setHidden:(totalRequests == 0)];
+    [totalInvites setIntValue:totalRequests];
 }
 
 -(void) reloadData
 {
     NSLog(@"reload");
     [smartView deselectAll:nil];
-    if (model_ == nil)
+    if (convModel_ == nil)
         return;
 
-    if (!model_->owner.contactModel->hasPendingRequests()) {
+    [self reloadSelectorNotifications];
+
+    if (!convModel_->owner.contactModel->hasPendingRequests()) {
         if (currentFilterType == lrc::api::profile::Type::PENDING) {
             [self selectConversationList];
         }
         if (selectorIsPresent) {
-            [listTypeSelector removeFromSuperview];
+            listTypeSelectorHeight.constant = 0.0;
+            [listTypeSelector setHidden:YES];
             selectorIsPresent = false;
         }
     } else {
         if (!selectorIsPresent) {
-            // First we restore the selector with selection on "Conversations"
-            [self.view addSubview:listTypeSelector];
             [listTypeSelector setSelected:YES forSegment:CONVERSATION_SEG];
-
-            // Then constraints are recreated (as these are lost when calling removeFromSuperview)
-            [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[searchField]-8-[listTypeSelector]"
-                                                                              options:0
-                                                                              metrics:nil
-                                                                                views:NSDictionaryOfVariableBindings(searchField, listTypeSelector)]];
-            [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[listTypeSelector]-8-[tabbar]"
-                                                                              options:0
-                                                                              metrics:nil
-                                                                                views:NSDictionaryOfVariableBindings(listTypeSelector, tabbar)]];
-            [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-20-[listTypeSelector]-20-|"
-                                                                              options:0
-                                                                              metrics:nil
-                                                                                views:NSDictionaryOfVariableBindings(listTypeSelector)]];
+            listTypeSelectorHeight.constant = 18.0;
+            [listTypeSelector setHidden:NO];
             selectorIsPresent = true;
         }
     }
 
     [smartView reloadData];
 
-    if (!selectedUid_.empty() && model_ != nil) {
-        auto it = getConversationFromUid(selectedUid_, *model_);
-        if (it != model_->allFilteredConversations().end()) {
-            NSIndexSet* indexSet = [NSIndexSet indexSetWithIndex:(it - model_->allFilteredConversations().begin())];
+    if (!selectedUid_.empty() && convModel_ != nil) {
+        auto it = getConversationFromUid(selectedUid_, *convModel_);
+        if (it != convModel_->allFilteredConversations().end()) {
+            NSIndexSet* indexSet = [NSIndexSet indexSetWithIndex:(it - convModel_->allFilteredConversations().begin())];
             [smartView selectRowIndexes:indexSet byExtendingSelection:NO];
         }
     }
@@ -180,69 +205,80 @@
 
 -(void) reloadConversationWithUid:(NSString *)uid
 {
-    if (model_ != nil) {
-        auto it = getConversationFromUid(std::string([uid UTF8String]), *model_);
-        if (it != model_->allFilteredConversations().end()) {
-            NSIndexSet* indexSet = [NSIndexSet indexSetWithIndex:(it - model_->allFilteredConversations().begin())];
-            NSLog(@"reloadConversationWithUid: %@", uid);
-            [smartView reloadDataForRowIndexes:indexSet
-                                 columnIndexes:[NSIndexSet indexSetWithIndex:0]];
-        }
+    if (convModel_ == nil) {
+        return;
+    }
+
+    auto it = getConversationFromUid(std::string([uid UTF8String]), *convModel_);
+    if (it != convModel_->allFilteredConversations().end()) {
+        NSIndexSet* indexSet = [NSIndexSet indexSetWithIndex:(it - convModel_->allFilteredConversations().begin())];
+        NSLog(@"reloadConversationWithUid: %@", uid);
+        [smartView reloadDataForRowIndexes:indexSet
+                             columnIndexes:[NSIndexSet indexSetWithIndex:0]];
     }
 }
 
 - (BOOL)setConversationModel:(lrc::api::ConversationModel *)conversationModel
 {
-    if (model_ != conversationModel) {
-        model_ = conversationModel;
-        selectedUid_.clear(); // Clear selected conversation as the selected account is being changed
-        QObject::disconnect(modelSortedConnection_);
-        QObject::disconnect(modelUpdatedConnection_);
-        QObject::disconnect(filterChangedConnection_);
-        QObject::disconnect(newConversationConnection_);
-        QObject::disconnect(conversationRemovedConnection_);
-        QObject::disconnect(interactionStatusUpdatedConnection_);
-        QObject::disconnect(conversationClearedConnection);
-        [self reloadData];
-        if (model_ != nil) {
-            modelSortedConnection_ = QObject::connect(model_, &lrc::api::ConversationModel::modelSorted,
-                                                      [self] (){
-                                                          [self reloadData];
-                                                      });
-            modelUpdatedConnection_ = QObject::connect(model_, &lrc::api::ConversationModel::conversationUpdated,
-                                                       [self] (const std::string& uid){
-                                                           [self reloadConversationWithUid: [NSString stringWithUTF8String:uid.c_str()]];
-                                                       });
-            filterChangedConnection_ = QObject::connect(model_, &lrc::api::ConversationModel::filterChanged,
+    if (convModel_ == conversationModel) {
+        return false;
+    }
+
+    convModel_ = conversationModel;
+    selectedUid_.clear(); // Clear selected conversation as the selected account is being changed
+    QObject::disconnect(modelSortedConnection_);
+    QObject::disconnect(modelUpdatedConnection_);
+    QObject::disconnect(filterChangedConnection_);
+    QObject::disconnect(newConversationConnection_);
+    QObject::disconnect(conversationRemovedConnection_);
+    QObject::disconnect(conversationClearedConnection);
+    QObject::disconnect(interactionStatusUpdatedConnection_);
+    QObject::disconnect(newInteractionConnection_);
+    [self reloadData];
+    if (convModel_ != nil) {
+        modelSortedConnection_ = QObject::connect(convModel_, &lrc::api::ConversationModel::modelSorted,
                                                         [self] (){
                                                             [self reloadData];
                                                         });
-            newConversationConnection_ = QObject::connect(model_, &lrc::api::ConversationModel::newConversation,
-                                                          [self] (const std::string& uid) {
-                                                              [self reloadData];
-                                                              [self updateConversationForNewContact:[NSString stringWithUTF8String:uid.c_str()]];
-                                                          });
-            conversationRemovedConnection_ = QObject::connect(model_, &lrc::api::ConversationModel::conversationRemoved,
-                                                              [self] (){
-                                                                  [self reloadData];
-                                                              });
-            conversationClearedConnection = QObject::connect(model_, &lrc::api::ConversationModel::conversationCleared,
-                                                              [self] (const std::string& id){
-                                                                  [self deselect];
-                                                                  [delegate listTypeChanged];
-                                                              });
-            interactionStatusUpdatedConnection_ = QObject::connect(model_, &lrc::api::ConversationModel::interactionStatusUpdated,
-                                                                   [self] (const std::string& convUid) {
-                                                                       if (convUid != selectedUid_)
-                                                                           return;
-                                                                       [self reloadConversationWithUid: [NSString stringWithUTF8String:convUid.c_str()]];
-                                                                   });
-            model_->setFilter(""); // Reset the filter
-        }
-        [searchField setStringValue:@""];
-        return YES;
+        modelUpdatedConnection_ = QObject::connect(convModel_, &lrc::api::ConversationModel::conversationUpdated,
+                                                        [self] (const std::string& convUid){
+                                                            [self reloadConversationWithUid: [NSString stringWithUTF8String:convUid.c_str()]];
+                                                        });
+        filterChangedConnection_ = QObject::connect(convModel_, &lrc::api::ConversationModel::filterChanged,
+                                                        [self] (){
+                                                            [self reloadData];
+                                                        });
+        newConversationConnection_ = QObject::connect(convModel_, &lrc::api::ConversationModel::newConversation,
+                                                        [self] (const std::string& convUid) {
+                                                            [self reloadData];
+                                                            [self updateConversationForNewContact:[NSString stringWithUTF8String:convUid.c_str()]];
+                                                        });
+        conversationRemovedConnection_ = QObject::connect(convModel_, &lrc::api::ConversationModel::conversationRemoved,
+                                                        [self] (){
+                                                            [delegate listTypeChanged];
+                                                            [self reloadData];
+                                                        });
+        conversationClearedConnection = QObject::connect(convModel_, &lrc::api::ConversationModel::conversationCleared,
+                                                        [self] (const std::string& convUid){
+                                                            [self deselect];
+                                                            [delegate listTypeChanged];
+                                                        });
+        interactionStatusUpdatedConnection_ = QObject::connect(convModel_, &lrc::api::ConversationModel::interactionStatusUpdated,
+                                                        [self] (const std::string& convUid) {
+                                                            if (convUid != selectedUid_)
+                                                                return;
+                                                            [self reloadConversationWithUid: [NSString stringWithUTF8String:convUid.c_str()]];
+                                                        });
+        newInteractionConnection_ = QObject::connect(convModel_, &lrc::api::ConversationModel::newInteraction,
+                                                        [self](const std::string& convUid, uint64_t interactionId, const lrc::api::interaction::Info& interaction){
+                                                            if (convUid == selectedUid_) {
+                                                                convModel_->clearUnreadInteractions(convUid);
+                                                            }
+                                                        });
+        convModel_->setFilter(""); // Reset the filter
     }
-    return NO;
+    [searchField setStringValue:@""];
+    return true;
 }
 
 -(void)selectConversation:(const lrc::api::conversation::Info&)conv model:(lrc::api::ConversationModel*)model;
@@ -253,13 +289,15 @@
 
     [self setConversationModel:model];
 
-    if (model_ != nil) {
-        auto it = getConversationFromUid(selectedUid_, *model_);
-        if (it != model_->allFilteredConversations().end()) {
-            NSIndexSet* indexSet = [NSIndexSet indexSetWithIndex:(it - model_->allFilteredConversations().begin())];
-            [smartView selectRowIndexes:indexSet byExtendingSelection:NO];
-            selectedUid_ = uid;
-        }
+    if (convModel_ == nil) {
+        return;
+    }
+
+    auto it = getConversationFromUid(selectedUid_, *convModel_);
+    if (it != convModel_->allFilteredConversations().end()) {
+        NSIndexSet* indexSet = [NSIndexSet indexSetWithIndex:(it - convModel_->allFilteredConversations().begin())];
+        [smartView selectRowIndexes:indexSet byExtendingSelection:NO];
+        selectedUid_ = uid;
     }
 }
 
@@ -270,7 +308,7 @@
 }
 
 -(void) clearConversationModel {
-    model_ = nil;
+    convModel_ = nil;
     [self deselect];
     [smartView reloadData];
     if (selectorIsPresent) {
@@ -281,18 +319,19 @@
 
 - (IBAction) listTypeChanged:(id)sender
 {
+    selectedUid_.clear();
     NSInteger selectedItem = [sender selectedSegment];
     switch (selectedItem) {
         case CONVERSATION_SEG:
             if (currentFilterType != lrc::api::profile::Type::RING) {
-                model_->setFilter(lrc::api::profile::Type::RING);
+                convModel_->setFilter(lrc::api::profile::Type::RING);
                 [delegate listTypeChanged];
                 currentFilterType = lrc::api::profile::Type::RING;
             }
             break;
         case REQUEST_SEG:
             if (currentFilterType != lrc::api::profile::Type::PENDING) {
-                model_->setFilter(lrc::api::profile::Type::PENDING);
+                convModel_->setFilter(lrc::api::profile::Type::PENDING);
                 [delegate listTypeChanged];
                 currentFilterType = lrc::api::profile::Type::PENDING;
             }
@@ -311,8 +350,8 @@
     // Do not invert order of the next two lines or stack overflow
     // may happen on -(void) reloadData call if filter is currently set to PENDING
     currentFilterType = lrc::api::profile::Type::RING;
-    model_->setFilter(lrc::api::profile::Type::RING);
-    model_->setFilter("");
+    convModel_->setFilter(lrc::api::profile::Type::RING);
+    convModel_->setFilter("");
 }
 
 -(void) selectPendingList
@@ -322,8 +361,8 @@
     [listTypeSelector setSelectedSegment:REQUEST_SEG];
 
     currentFilterType = lrc::api::profile::Type::PENDING;
-    model_->setFilter(lrc::api::profile::Type::PENDING);
-    model_->setFilter("");
+    convModel_->setFilter(lrc::api::profile::Type::PENDING);
+    convModel_->setFilter("");
 }
 
 #pragma mark - NSTableViewDelegate methods
@@ -342,15 +381,26 @@
 {
     NSInteger row = [notification.object selectedRow];
 
+    [smartView enumerateAvailableRowViewsUsingBlock:^(NSTableRowView *rowView, NSInteger row){
+        NSTableRowView* cellRowView = [smartView rowViewAtRow:row makeIfNecessary:NO];
+        if(rowView.selected){
+            cellRowView.backgroundColor = [NSColor controlColor];
+        }else{
+            cellRowView.backgroundColor = [NSColor whiteColor];
+        }
+    }];
+
     if (row == -1)
         return;
-    if (model_ == nil)
+    if (convModel_ == nil)
         return;
 
-    auto uid = model_->filteredConversation(row).uid;
+    auto uid = convModel_->filteredConversation(row).uid;
     if (selectedUid_ != uid) {
         selectedUid_ = uid;
-        model_->selectConversation(uid);
+        convModel_->selectConversation(uid);
+        convModel_->clearUnreadInteractions(uid);
+        [self reloadSelectorNotifications];
     }
 }
 
@@ -361,56 +411,105 @@
 
 - (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
 {
-    if (model_ == nil)
+    if (convModel_ == nil)
         return nil;
 
-    auto conversation = model_->filteredConversation(row);
+    auto conversation = convModel_->filteredConversation(row);
     NSTableCellView* result;
 
     result = [tableView makeViewWithIdentifier:@"MainCell" owner:tableView];
-//    NSTextField* details = [result viewWithTag:DETAILS_TAG];
 
-    NSMutableArray* controls = [NSMutableArray arrayWithObject:[result viewWithTag:CALL_BUTTON_TAG]];
-    [((ContextualTableCellView*) result) setContextualsControls:controls];
-    [((ContextualTableCellView*) result) setShouldBlurParentView:YES];
-
-    //    if (auto call = RecentModel::instance().getActiveCall(qIdx)) {
-    //        [details setStringValue:call->roleData((int)Ring::Role::FormattedState).toString().toNSString()];
-    //        [((ContextualTableCellView*) result) setActiveState:YES];
-    //    } else {
-    //        [details setStringValue:qIdx.data((int)Ring::Role::FormattedLastUsed).toString().toNSString()];
-    //        [((ContextualTableCellView*) result) setActiveState:NO];
-    //    }
-
-    NSTextField* unreadCount = [result viewWithTag:TXT_BUTTON_TAG];
+    NSTextField* unreadCount = [result viewWithTag:NOTIFICATONS_TAG];
     [unreadCount setHidden:(conversation.unreadMessages == 0)];
     [unreadCount setIntValue:conversation.unreadMessages];
-
     NSTextField* displayName = [result viewWithTag:DISPLAYNAME_TAG];
-    NSString* displayNameString = bestNameForConversation(conversation, *model_);
-    NSString* displayIDString = bestIDForConversation(conversation, *model_);
+    NSTextField* displayRingID = [result viewWithTag:RING_ID_LABEL];
+    NSString* displayNameString = bestNameForConversation(conversation, *convModel_);
+    NSString* displayIDString = bestIDForConversation(conversation, *convModel_);
     if(displayNameString.length == 0 || [displayNameString isEqualToString:displayIDString]) {
-        NSTextField* displayRingID = [result viewWithTag:RING_ID_LABEL];
         [displayName setStringValue:displayIDString];
         [displayRingID setHidden:YES];
     }
     else {
-        NSTextField* displayRingID = [result viewWithTag:RING_ID_LABEL];
         [displayName setStringValue:displayNameString];
         [displayRingID setStringValue:displayIDString];
         [displayRingID setHidden:NO];
     }
-    NSImageView* photoView = [result viewWithTag:IMAGE_TAG];
 
+    NSImageView* photoView = [result viewWithTag:IMAGE_TAG];
     auto& imageManip = reinterpret_cast<Interfaces::ImageManipulationDelegate&>(GlobalInstances::pixmapManipulator());
-    [photoView setImage:QtMac::toNSImage(qvariant_cast<QPixmap>(imageManip.conversationPhoto(conversation, model_->owner)))];
+    [photoView setImage:QtMac::toNSImage(qvariant_cast<QPixmap>(imageManip.conversationPhoto(conversation, convModel_->owner)))];
 
     NSView* presenceView = [result viewWithTag:PRESENCE_TAG];
-    if (model_->owner.contactModel->getContact(conversation.participants[0]).isPresent) {
+    auto contact = convModel_->owner.contactModel->getContact(conversation.participants[0]);
+    if (contact.isPresent) {
         [presenceView setHidden:NO];
     } else {
         [presenceView setHidden:YES];
     }
+    NSTextField* lastInteractionDate = [result viewWithTag:DATE_TAG];
+    NSTextField* interactionSnippet = [result viewWithTag:SNIPPET_TAG];
+    NSButton* addContactButton = [result viewWithTag:ADD_BUTTON_TAG];
+    NSButton* refuseContactButton = [result viewWithTag:REFUSE_BUTTON_TAG];
+    NSButton* blockContactButton = [result viewWithTag:BLOCK_BUTTON_TAG];
+    [addContactButton setHidden:YES];
+    [refuseContactButton setHidden:YES];
+    [blockContactButton setHidden:YES];
+
+    if (profileType(conversation, *convModel_) == lrc::api::profile::Type::PENDING) {
+        [lastInteractionDate setHidden:true];
+        [interactionSnippet setHidden:true];
+        [addContactButton setHidden:NO];
+        [refuseContactButton setHidden:NO];
+        [blockContactButton setHidden:NO];
+        [addContactButton setAction:@selector(acceptInvitation:)];
+        [addContactButton setTarget:self];
+        [refuseContactButton setAction:@selector(refuseInvitation:)];
+        [refuseContactButton setTarget:self];
+        [blockContactButton setAction:@selector(blockPendingContact:)];
+        [blockContactButton setTarget:self];
+        return result;
+    }
+
+    [lastInteractionDate setHidden:false];
+
+    [interactionSnippet setHidden:false];
+
+    auto lastUid = conversation.lastMessageUid;
+    if (conversation.interactions.find(lastUid) != conversation.interactions.end()) {
+        // last interaction snippet
+        std::string lastInteractionSnippet = conversation.interactions[lastUid].body;
+        std::stringstream ss(lastInteractionSnippet);
+        std::getline(ss, lastInteractionSnippet);
+        NSString* lastInteractionSnippetFixedString = [[NSString stringWithUTF8String:lastInteractionSnippet.c_str()]
+                                                       stringByReplacingOccurrencesOfString:@"🕽" withString:@""];
+        lastInteractionSnippetFixedString = [lastInteractionSnippetFixedString stringByReplacingOccurrencesOfString:@"📞" withString:@""];
+        if (conversation.interactions[lastUid].type == lrc::api::interaction::Type::OUTGOING_DATA_TRANSFER
+            || conversation.interactions[lastUid].type == lrc::api::interaction::Type::INCOMING_DATA_TRANSFER) {
+            if (([lastInteractionSnippetFixedString rangeOfString:@"/"].location != NSNotFound)) {
+                NSArray *listItems = [lastInteractionSnippetFixedString componentsSeparatedByString:@"/"];
+                NSString* name = listItems.lastObject;
+                lastInteractionSnippetFixedString = name;
+            }
+        }
+        [interactionSnippet setStringValue:lastInteractionSnippetFixedString];
+
+        // last interaction date/time
+        std::time_t lastInteractionTimestamp = conversation.interactions[lastUid].timestamp;
+        std::time_t now = std::time(nullptr);
+        char interactionDay[64];
+        char nowDay[64];
+        std::strftime(interactionDay, sizeof(interactionDay), "%D", std::localtime(&lastInteractionTimestamp));
+        std::strftime(nowDay, sizeof(nowDay), "%D", std::localtime(&now));
+        if (std::string(interactionDay) == std::string(nowDay)) {
+            char interactionTime[64];
+            std::strftime(interactionTime, sizeof(interactionTime), "%R", std::localtime(&lastInteractionTimestamp));
+            [lastInteractionDate setStringValue:[NSString stringWithUTF8String:interactionTime]];
+        } else {
+            [lastInteractionDate setStringValue:[NSString stringWithUTF8String:interactionDay]];
+        }
+    }
+
     return result;
 }
 
@@ -423,9 +522,8 @@
 
 - (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
 {
-    if (tableView == smartView) {
-        if (model_ != nullptr)
-            return model_->allFilteredConversations().size();
+    if (tableView == smartView && convModel_ != nullptr) {
+        return convModel_->allFilteredConversations().size();
     }
 
     return 0;
@@ -442,16 +540,16 @@
 
     if (row == -1)
         return;
-    if (model_ == nil)
+    if (convModel_ == nil)
         return;
 
-    auto conv = model_->filteredConversation(row);
+    auto conv = convModel_->filteredConversation(row);
     auto& callId = conv.callId;
 
     if (callId.empty())
         return;
 
-    auto* callModel = model_->owner.callModel.get();
+    auto* callModel = convModel_->owner.callModel.get();
     callModel->hangUp(callId);
 }
 
@@ -468,14 +566,16 @@
 
 - (void) processSearchFieldInput
 {
-    if (model_ == nil)
-    return;
-    model_->setFilter(std::string([[searchField stringValue] UTF8String]));
+    if (convModel_ == nil) {
+        return;
+    }
+
+    convModel_->setFilter(std::string([[searchField stringValue] UTF8String]));
 }
 
 -(const lrc::api::account::Info&) chosenAccount
 {
-    return model_->owner;
+    return convModel_->owner;
 }
 
 - (void) clearSearchField
@@ -485,18 +585,18 @@
 }
 
 -(void)updateConversationForNewContact:(NSString *)uId {
-    if (model_ == nil) {
+    if (convModel_ == nil) {
         return;
     }
     [self clearSearchField];
     auto uid = std::string([uId UTF8String]);
-    auto it = getConversationFromUid(uid, *model_);
-    if (it != model_->allFilteredConversations().end()) {
+    auto it = getConversationFromUid(uid, *convModel_);
+    if (it != convModel_->allFilteredConversations().end()) {
         @try {
-            auto contact = model_->owner.contactModel->getContact(it->participants[0]);
+            auto contact = convModel_->owner.contactModel->getContact(it->participants[0]);
             if (!contact.profileInfo.uri.empty() && contact.profileInfo.uri.compare(selectedUid_) == 0) {
                 selectedUid_ = uid;
-                model_->selectConversation(uid);
+                convModel_->selectConversation(uid);
             }
         } @catch (NSException *exception) {
             return;
@@ -523,25 +623,25 @@
     if (commandSelector != @selector(insertNewline:) || [[searchField stringValue] isEqual:@""]) {
         return NO;
     }
-    if (model_ == nil) {
+    if (convModel_ == nil) {
         [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 (model_->allFilteredConversations().size() <= 0) {
+    if (convModel_->allFilteredConversations().size() <= 0) {
         return YES;
     }
-    auto model = model_->filteredConversation(0);
+    auto model = convModel_->filteredConversation(0);
     auto uid = model.uid;
     if (selectedUid_ == uid) {
         return YES;
     }
     @try {
-        auto contact = model_->owner.contactModel->getContact(model.participants[0]);
+        auto contact = convModel_->owner.contactModel->getContact(model.participants[0]);
         if ((contact.profileInfo.uri.empty() && contact.profileInfo.type != lrc::api::profile::Type::SIP) || contact.profileInfo.type == lrc::api::profile::Type::INVALID) {
             return YES;
         }
         selectedUid_ = uid;
-        model_->selectConversation(uid);
+        convModel_->selectConversation(uid);
         [self.view.window makeFirstResponder: smartView];
         return YES;
     } @catch (NSException *exception) {
@@ -581,24 +681,24 @@
 {
     if ([smartView selectedRow] == -1)
         return;
-    if (model_ == nil)
+    if (convModel_ == nil)
         return ;
 
-    auto uid = model_->filteredConversation([smartView selectedRow]).uid;
-    model_->makePermanent(uid);
+    auto uid = convModel_->filteredConversation([smartView selectedRow]).uid;
+    convModel_->makePermanent(uid);
 }
 
 #pragma mark - ContextMenuDelegate
 
 - (NSMenu*) contextualMenuForRow:(int) index
 {
-    if (model_ == nil)
+    if (convModel_ == nil)
         return nil;
 
-    auto conversation = model_->filteredConversation(NSInteger(index));
+    auto conversation = convModel_->filteredConversation(NSInteger(index));
 
     @try {
-        auto contact = model_->owner.contactModel->getContact(conversation.participants[0]);
+        auto contact = convModel_->owner.contactModel->getContact(conversation.participants[0]);
         if (contact.profileInfo.type == lrc::api::profile::Type::INVALID) {
             return nil;
         }
@@ -671,7 +771,7 @@
     }
     NSString * convUId = (NSString*)menuObject;
     std::string conversationID = std::string([convUId UTF8String]);
-    model_->makePermanent(conversationID);
+    convModel_->makePermanent(conversationID);
 }
 
 - (void) blockContact: (NSMenuItem* ) item  {
@@ -681,8 +781,8 @@
     }
     NSString * convUId = (NSString*)menuObject;
     std::string conversationID = std::string([convUId UTF8String]);
-    model_->clearHistory(conversationID);
-    model_->removeConversation(conversationID, true);
+    //convModel_->clearHistory(conversationID);
+    convModel_->removeConversation(conversationID, true);
 }
 
 - (void) audioCall: (NSMenuItem* ) item  {
@@ -692,7 +792,7 @@
     }
     NSString * convUId = (NSString*)menuObject;
     std::string conversationID = std::string([convUId UTF8String]);
-    model_->placeAudioOnlyCall(conversationID);
+    convModel_->placeAudioOnlyCall(conversationID);
 
 }
 
@@ -703,7 +803,7 @@
     }
     NSString * convUId = (NSString*)menuObject;
     std::string conversationID = std::string([convUId UTF8String]);
-    model_->placeCall(conversationID);
+    convModel_->placeCall(conversationID);
 }
 
 - (void) clearConversation:(NSMenuItem* ) item  {
@@ -713,7 +813,57 @@
     }
     NSString * convUId = (NSString*)menuObject;
     std::string conversationID = std::string([convUId UTF8String]);
-    model_->clearHistory(conversationID);
+    convModel_->clearHistory(conversationID);
+}
+
+- (void)acceptInvitation:(id)sender {
+    NSInteger row = [smartView rowForView:sender];
+
+    if (row == -1)
+        return;
+    if (convModel_ == nil)
+        return;
+
+    auto conv = convModel_->filteredConversation(row);
+    auto& convID = conv.Info::uid;
+
+    if (convID.empty())
+        return;
+    convModel_->makePermanent(convID);
+}
+
+- (void)refuseInvitation:(id)sender {
+    NSInteger row = [smartView rowForView:sender];
+
+    if (row == -1)
+        return;
+    if (convModel_ == nil)
+        return;
+
+    auto conv = convModel_->filteredConversation(row);
+    auto& convID = conv.Info::uid;
+
+    if (convID.empty())
+        return;
+    convModel_->removeConversation(convID);
+}
+
+- (void)blockPendingContact:(id)sender {
+    NSInteger row = [smartView rowForView:sender];
+
+    if (row == -1)
+        return;
+    if (convModel_ == nil)
+        return;
+
+    auto conv = convModel_->filteredConversation(row);
+    auto& convID = conv.Info::uid;
+
+    if (convID.empty())
+        return;
+    convModel_->removeConversation(convID, true);
+    [self deselect];
+    [delegate listTypeChanged];
 }
 
 @end