diff --git a/src/api/conversationmodel.h b/src/api/conversationmodel.h
index a1797bd3cc009084f23eb877619d38e8d4d3112f..67934a397520b0a1477653d104e011548b3aa6e0 100644
--- a/src/api/conversationmodel.h
+++ b/src/api/conversationmodel.h
@@ -289,7 +289,7 @@ public:
 
     void getTransferInfo(const QString& conversationId,
                          const QString& interactionId,
-                         api::datatransfer::Info& info);
+                         api::datatransfer::Info& info) const;
     /**
      * @param convUid, uid of the conversation
      * @return the number of unread messages for the conversation
diff --git a/src/conversationmodel.cpp b/src/conversationmodel.cpp
index 105e4f98c6f60b69d874bb5df94688dc802ac0ea..2484e3a93c3b7fe92818f68140556c8ca0c873f5 100644
--- a/src/conversationmodel.cpp
+++ b/src/conversationmodel.cpp
@@ -194,10 +194,10 @@ public:
     /**
      * Handle data transfer progression
      */
-    void updateTransfer(QTimer* timer,
-                        const QString& conversation,
-                        int conversationIdx,
-                        const QString& interactionId);
+    void updateTransferProgress(QTimer* timer,
+                                const QString& conversation,
+                                int conversationIdx,
+                                const QString& interactionId);
 
     bool usefulDataFromDataTransfer(const QString& fileId,
                                     const datatransfer::Info& info,
@@ -1433,6 +1433,7 @@ ConversationModel::setInteractionRead(const QString& convId, const QString& inte
                 return;
             }
             it->second.isRead = true;
+            interactions->emitDataChanged(it, {MessageList::Role::IsRead});
             if (pimpl_->conversations[conversationIdx].unreadMessages != 0)
                 pimpl_->conversations[conversationIdx].unreadMessages -= 1;
             itCopy = it->second;
@@ -3130,14 +3131,16 @@ ConversationModelPimpl::addOrUpdateCallMessage(const QString& callId,
     auto msgId = storage::addOrUpdateMessage(db, conv_it->uid, msg, callId);
     // now set the formatted call message string in memory only
     msg.body = storage::getCallInteractionString(uriString, duration);
-    auto newInteraction = conv_it->interactions->find(msgId) == conv_it->interactions->end();
+    auto interactionIt = conv_it->interactions->find(msgId);
+    auto newInteraction = interactionIt == conv_it->interactions->end();
     if (newInteraction) {
         conv_it->lastMessageUid = msgId;
         std::lock_guard<std::mutex> lk(interactionsLocks[conv_it->uid]);
         conv_it->interactions->emplace(msgId, msg);
     } else {
         std::lock_guard<std::mutex> lk(interactionsLocks[conv_it->uid]);
-        (*(conv_it->interactions))[msgId] = msg;
+        interactionIt->second = msg;
+        conv_it->interactions->emitDataChanged(interactionIt);
     }
 
     if (newInteraction)
@@ -3337,6 +3340,7 @@ ConversationModelPimpl::slotUpdateInteractionStatus(const QString& accountId,
             auto messageId = conversation.lastDisplayedMessageUid.find(peerId);
             if (it != interactions->end()) {
                 it->second.status = newStatus;
+                interactions->emitDataChanged(it, {MessageList::Role::Status});
                 bool interactionDisplayed = newStatus == interaction::Status::DISPLAYED
                                             && isOutgoing(it->second);
                 if (messageId != conversation.lastDisplayedMessageUid.end()) {
@@ -3540,6 +3544,7 @@ ConversationModel::cancelTransfer(const QString& convUid, const QString& fileId)
         auto it = interactions->find(fileId);
         if (it != interactions->end()) {
             it->second.status = interaction::Status::TRANSFER_CANCELED;
+            interactions->emitDataChanged(it, {MessageList::Role::Status});
 
             // update information in the db
             storage::updateInteractionStatus(pimpl_->db,
@@ -3565,7 +3570,7 @@ ConversationModel::cancelTransfer(const QString& convUid, const QString& fileId)
 void
 ConversationModel::getTransferInfo(const QString& conversationId,
                                    const QString& interactionId,
-                                   datatransfer::Info& info)
+                                   datatransfer::Info& info) const
 {
     auto convOpt = getConversationForUid(conversationId);
     if (!convOpt)
@@ -3818,6 +3823,8 @@ ConversationModelPimpl::acceptTransfer(const QString& convUid,
             if (it != interactions->end()) {
                 it->second.body = acceptedFilePath;
                 it->second.status = interaction::Status::TRANSFER_ACCEPTED;
+                using namespace MessageList;
+                interactions->emitDataChanged(it, {Role::Body, Role::Status});
                 emitUpdated = true;
                 itCopy = it->second;
             }
@@ -3895,7 +3902,7 @@ ConversationModelPimpl::slotTransferStatusOngoing(const QString& fileId, datatra
     auto conversationIdx = indexOf(conversationId);
     auto* timer = new QTimer();
     connect(timer, &QTimer::timeout, [=] {
-        updateTransfer(timer, conversationId, conversationIdx, interactionId);
+        updateTransferProgress(timer, conversationId, conversationIdx, interactionId);
     });
     timer->start(1000);
 }
@@ -3925,6 +3932,7 @@ ConversationModelPimpl::slotTransferStatusFinished(const QString& fileId, datatr
                 if (it->second.status == interaction::Status::TRANSFER_ONGOING) {
                     emitUpdated = true;
                     it->second.status = newStatus;
+                    interactions->emitDataChanged(it, {MessageList::Role::Status});
                     itCopy = it->second;
                 }
             }
@@ -4010,10 +4018,14 @@ ConversationModelPimpl::updateTransferStatus(const QString& fileId,
         auto it = interactions->find(interactionId);
         if (it != interactions->end()) {
             emitUpdated = true;
+            VectorInt roles;
             it->second.status = newStatus;
+            roles += MessageList::Role::Status;
             if (conversation.isSwarm()) {
                 it->second.body = info.path;
+                roles += MessageList::Role::Body;
             }
+            interactions->emitDataChanged(it, roles);
             itCopy = it->second;
         }
     }
@@ -4026,20 +4038,22 @@ ConversationModelPimpl::updateTransferStatus(const QString& fileId,
 }
 
 void
-ConversationModelPimpl::updateTransfer(QTimer* timer,
-                                       const QString& conversation,
-                                       int conversationIdx,
-                                       const QString& interactionId)
+ConversationModelPimpl::updateTransferProgress(QTimer* timer,
+                                               const QString& conversation,
+                                               int conversationIdx,
+                                               const QString& interactionId)
 {
     try {
         bool emitUpdated = false;
         interaction::Info itCopy;
         {
-            std::lock_guard<std::mutex> lk(interactionsLocks[conversations[conversationIdx].uid]);
+            auto convId = conversations[conversationIdx].uid;
+            std::lock_guard<std::mutex> lk(interactionsLocks[convId]);
             const auto& interactions = conversations[conversationIdx].interactions;
             const auto& it = interactions->find(interactionId);
             if (it != interactions->cend()
                 and it->second.status == interaction::Status::TRANSFER_ONGOING) {
+                interactions->emitDataChanged(it, {MessageList::Role::Status});
                 emitUpdated = true;
                 itCopy = it->second;
             }
diff --git a/src/messagelistmodel.cpp b/src/messagelistmodel.cpp
index d120c50e450e15c2a0b1241888a04b3068076eee..4546128f5f6742a77a5e6b6bf398d3877636c1e9 100644
--- a/src/messagelistmodel.cpp
+++ b/src/messagelistmodel.cpp
@@ -348,6 +348,8 @@ MessageListModel::dataForItem(item_t item, int indexRow, int role) const
         return QVariant(item.second.linkPreviewInfo);
     case Role::Linkified:
         return QVariant(item.second.linkified);
+    case Role::TransferName:
+        return QVariant(item.second.commit["displayName"]);
     default:
         return {};
     }
@@ -399,4 +401,35 @@ MessageListModel::linkifyMessage(const QString& messageId, const QString& linkif
     Q_EMIT dataChanged(modelIndex, modelIndex, {Role::Body, Role::Linkified});
 }
 
+void
+MessageListModel::emitBeginResetModel()
+{
+    Q_EMIT beginResetModel();
+}
+
+void
+MessageListModel::emitEndResetModel()
+{
+    Q_EMIT endResetModel();
+}
+
+void
+MessageListModel::emitDataChanged(iterator it, VectorInt roles)
+{
+    auto index = std::distance(begin(), it);
+    QModelIndex modelIndex = QAbstractListModel::index(index, 0);
+    Q_EMIT dataChanged(modelIndex, modelIndex, roles);
+}
+
+void
+MessageListModel::emitDataChanged(const QString& msgId, VectorInt roles)
+{
+    int index = getIndexOfMessage(msgId);
+    if (index == -1) {
+        return;
+    }
+    QModelIndex modelIndex = QAbstractListModel::index(index, 0);
+    Q_EMIT dataChanged(modelIndex, modelIndex, roles);
+}
+
 } // namespace lrc
diff --git a/src/messagelistmodel.h b/src/messagelistmodel.h
index 0f0d0f3c3162b9be42c2c82d08668148302ce427..79064983c16f5886e17f6a5904e0b942cd82b637 100644
--- a/src/messagelistmodel.h
+++ b/src/messagelistmodel.h
@@ -42,7 +42,8 @@ struct Info;
     X(IsRead) \
     X(Commit) \
     X(LinkPreviewInfo) \
-    X(Linkified)
+    X(Linkified) \
+    X(TransferName)
 
 namespace MessageList {
 Q_NAMESPACE
@@ -106,6 +107,15 @@ public:
     void addHyperlinkInfo(const QString& messageId, const QVariantMap& info);
     void linkifyMessage(const QString& messageId, const QString& linkified);
 
+    // use these if the underlying data model is changed from conversationmodel
+    // Note: this is not ideal, and this class should be refactored into a proper
+    // view model and absorb the interaction management logic to avoid exposing
+    // these emission wrappers
+    void emitBeginResetModel();
+    void emitEndResetModel();
+    void emitDataChanged(iterator it, VectorInt roles = {});
+    void emitDataChanged(const QString& msgId, VectorInt roles = {});
+
 protected:
     using Role = MessageList::Role;