diff --git a/src/call.cpp b/src/call.cpp
index 5ea31729d71bf3eba2956cc198ab7ec6b2f66e12..176532f105cf450f21affcf3cdbe90cfbbda7280 100644
--- a/src/call.cpp
+++ b/src/call.cpp
@@ -313,6 +313,8 @@ Call::Call(Call::State startState, const QString& peerName, ContactMethod* numbe
    d_ptr->m_Account          = account;
    d_ptr->m_PeerName         = peerName;
    d_ptr->m_pPeerContactMethod = number;
+   if (number)
+      connect(number, &ContactMethod::unreadTextMessageCountChanged, d_ptr, &CallPrivate::updated);
    d_ptr->m_pParentCall      = nullptr;
 
    emit changed();
@@ -1146,6 +1148,7 @@ void Call::setPeerContactMethod(ContactMethod* cm)
       return;
    }
    d_ptr->m_pPeerContactMethod = cm;
+   connect(cm, &ContactMethod::unreadTextMessageCountChanged, d_ptr, &CallPrivate::updated);
    setDialNumber(cm->uri());
 }
 
@@ -1288,8 +1291,10 @@ Call::State CallPrivate::stateChanged(const QString& newStateName)
 
    }
    if (q_ptr->lifeCycleState() != Call::LifeCycleState::CREATION && m_pDialNumber) {
-      if (!m_pPeerContactMethod)
+      if (!m_pPeerContactMethod) {
           m_pPeerContactMethod = PhoneDirectoryModel::instance().fromTemporary(m_pDialNumber);
+          connect(m_pPeerContactMethod, &ContactMethod::unreadTextMessageCountChanged, this, &CallPrivate::updated);
+      }
       m_pDialNumber->deleteLater();
       m_pDialNumber = nullptr;
    }
@@ -1724,8 +1729,10 @@ void CallPrivate::call()
 
     // Warning: m_pDialNumber can become nullptr when linking directly
     URI uri {peerCM->uri()};
-    if (!m_pPeerContactMethod)
+    if (!m_pPeerContactMethod) {
         m_pPeerContactMethod = PhoneDirectoryModel::instance().getNumber(uri, q_ptr->account());
+        connect(m_pPeerContactMethod, &ContactMethod::unreadTextMessageCountChanged, this, &CallPrivate::updated);
+    }
 
     // m_pDialNumber is now discarded
     m_pDialNumber->deleteLater();
@@ -1844,8 +1851,10 @@ void CallPrivate::start()
    qDebug() << "Starting call. callId : " << q_ptr  << "ConfId:" << q_ptr;
    emit q_ptr->changed();
    if (m_pDialNumber) {
-      if (!m_pPeerContactMethod)
+      if (!m_pPeerContactMethod) {
           m_pPeerContactMethod = PhoneDirectoryModel::instance().fromTemporary(m_pDialNumber);
+          connect(m_pPeerContactMethod, &ContactMethod::unreadTextMessageCountChanged, this, &CallPrivate::updated);
+      }
       m_pDialNumber->deleteLater();
       m_pDialNumber = nullptr;
    }
diff --git a/src/contactmethod.h b/src/contactmethod.h
index b823fe5ac225d7d15289d6d20b0fd931249c39b9..aff4ca2e5944e3c2333be872ee32d5d55c10a302 100644
--- a/src/contactmethod.h
+++ b/src/contactmethod.h
@@ -223,6 +223,8 @@ Q_SIGNALS:
    void lastUsedChanged(time_t t);
    ///The person attached to this CM has changed
    void contactChanged(Person* newContact, Person* oldContact);
+   /// The number of unread text messages has changed
+   void unreadTextMessageCountChanged();
 };
 
 Q_DECLARE_METATYPE(ContactMethod*)
diff --git a/src/media/textrecording.cpp b/src/media/textrecording.cpp
index 4aaa4ea8447787e242238b90ba5066dae61abdbd..c4f04a39ae4271e86a8905bba5d998cf1465da25 100644
--- a/src/media/textrecording.cpp
+++ b/src/media/textrecording.cpp
@@ -195,8 +195,13 @@ void Media::TextRecording::setAllRead()
             changed = true;
         }
     }
-    if (changed)
+    if (changed) {
+        // TODO: we assume that the CM is the same for now, and that at least some of the messages
+        //       are text
+        emit d_ptr->m_lNodes[0]->m_pContactMethod->unreadTextMessageCountChanged();
+        emit d_ptr->m_lNodes[0]->m_pContactMethod->changed();
         save();
+    }
 }
 
 /**
@@ -409,6 +414,10 @@ void Media::TextRecordingPrivate::insertNewMessage(const QMap<QString,QString>&
 
    cm->setLastUsed(currentTime);
    emit q_ptr->messageInserted(message, const_cast<ContactMethod*>(cm), direction);
+   if (!m->isRead) {
+      emit cm->unreadTextMessageCountChanged();
+      emit cm->changed();
+   }
 }
 
 void Serializable::Payload::read(const QJsonObject &json)
@@ -691,8 +700,14 @@ bool InstantMessagingModel::setData(const QModelIndex& idx, const QVariant &valu
     ::TextMessageNode* n = m_pRecording->d_ptr->m_lNodes[idx.row()];
     switch (role) {
         case (int)Media::TextRecording::Role::IsRead               :
-            n->m_pMessage->isRead = value.toBool();
-            emit dataChanged(idx,idx);
+            if (n->m_pMessage->isRead != value.toBool()) {
+                n->m_pMessage->isRead = value.toBool();
+                if (n->m_pMessage->m_HasText) {
+                    emit n->m_pContactMethod->unreadTextMessageCountChanged();
+                    emit n->m_pContactMethod->changed();
+                }
+                emit dataChanged(idx,idx);
+            }
             break;
         default:
             return false;
diff --git a/src/person.cpp b/src/person.cpp
index 0ff6dbffda56b933e0da7c87b627cb8420df534b..88c85bfca816d05265448265376992a0e506aaea 100644
--- a/src/person.cpp
+++ b/src/person.cpp
@@ -352,12 +352,14 @@ void Person::setContactMethods(ContactMethods numbers)
    for (ContactMethod* n : d_ptr->m_Numbers) {
       disconnect(n,SIGNAL(presentChanged(bool)),this,SLOT(slotPresenceChanged()));
       disconnect(n, &ContactMethod::lastUsedChanged, d_ptr, &PersonPrivate::slotLastUsedTimeChanged);
+      disconnect(n, &ContactMethod::unreadTextMessageCountChanged, d_ptr, &PersonPrivate::changed);
    }
    d_ptr->m_Numbers = numbers;
 
    for (ContactMethod* n : d_ptr->m_Numbers) {
       connect(n,SIGNAL(presentChanged(bool)),this,SLOT(slotPresenceChanged()));
       connect(n, &ContactMethod::lastUsedChanged, d_ptr, &PersonPrivate::slotLastUsedTimeChanged);
+      connect(n, &ContactMethod::unreadTextMessageCountChanged, d_ptr, &PersonPrivate::changed);
    }
 
    d_ptr->phoneNumbersChanged();