diff --git a/src/localtextrecordingcollection.cpp b/src/localtextrecordingcollection.cpp index 91623caa01de09b763dbb3458531287407b43047..a9f46cd281240bdc442654099de1354507de6991 100644 --- a/src/localtextrecordingcollection.cpp +++ b/src/localtextrecordingcollection.cpp @@ -171,9 +171,57 @@ bool LocalTextRecordingCollection::isEnabled() const bool LocalTextRecordingCollection::load() { - //This collection is special as it use the history collection - //as its source, there is no loading - return true; + // load all text recordings so we can recover CMs that are not in the call history + QDir dir(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/text/"); + if (dir.exists()) { + // get .json files, sorted by time, latest first + QStringList filters; + filters << "*.json"; + auto list = dir.entryInfoList(filters, QDir::Files | QDir::NoSymLinks | QDir::Readable, QDir::Time); + + for (int i = 0; i < list.size(); ++i) { + QFileInfo fileInfo = list.at(i); + + QString content; + QFile file(fileInfo.absoluteFilePath()); + if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { + content = QString::fromUtf8(file.readAll()); + } else { + qWarning() << "Could not open text recording json file"; + } + + if (!content.isEmpty()) { + QJsonParseError err; + QJsonDocument loadDoc = QJsonDocument::fromJson(content.toUtf8(), &err); + + if (err.error == QJsonParseError::ParseError::NoError) { + Media::TextRecording* r = Media::TextRecording::fromJson({loadDoc.object()}); + + editor<Media::Recording>()->addExisting(r); + r->setCollection(this); + + // get CMs from recording + for (ContactMethod *cm : r->peers()) { + // since we load the recordings in order from newest to oldest, if there is + // more than one found associated with a CM, we take the newest one + if (!cm->d_ptr->m_pTextRecording) { + cm->d_ptr->setTextRecording(r); + } else { + qWarning() << "CM already has text recording" << cm; + } + } + } else { + qWarning() << "Error Decoding Text Message History Json" << err.errorString(); + } + } else { + qWarning() << "Text recording file is empty"; + } + } + } + + // always return true, even if noting was loaded, since the collection can still be used to + // save files + return true; } bool LocalTextRecordingCollection::reload() diff --git a/src/media/textrecording.cpp b/src/media/textrecording.cpp index 5c99c66cd9cec703b8c7288998bb7fea837fb45c..215631de29b74b8c4ceefeffc6b9b71fff275441 100644 --- a/src/media/textrecording.cpp +++ b/src/media/textrecording.cpp @@ -208,6 +208,19 @@ void Media::TextRecording::setAllRead() } } +QVector<ContactMethod*> Media::TextRecording::peers() const +{ + QVector<ContactMethod*> cms; + + for (const Serializable::Peers* peers : d_ptr->m_lAssociatedPeers) { + for (const Serializable::Peer* peer : peers->peers) { + cms << peer->m_pContactMethod; + } + } + + return cms; +} + /** * I (Emmanuel Lepage) is in the process of writing a better one for this that * can be upstreamed into Qt (there is interest in merging a generic QVariant @@ -304,40 +317,61 @@ QHash<QByteArray,QByteArray> Media::TextRecordingPrivate::toJsons() const Media::TextRecording* Media::TextRecording::fromJson(const QList<QJsonObject>& items, const ContactMethod* cm) { - TextRecording* t = new TextRecording(); + TextRecording* t = new TextRecording(); - //Load the history data - for (const QJsonObject& obj : items) { - Serializable::Peers* p = SerializableEntityManager::fromJson(obj,cm); - t->d_ptr->m_lAssociatedPeers << p; - } + //Load the history data + for (const QJsonObject& obj : items) { + Serializable::Peers* p = SerializableEntityManager::fromJson(obj,cm); + t->d_ptr->m_lAssociatedPeers << p; + } - //Create the model - t->instantMessagingModel(); - - //Reconstruct the conversation - //TODO do it right, right now it flatten the graph - for (const Serializable::Peers* p : t->d_ptr->m_lAssociatedPeers) { - for (const Serializable::Group* g : p->groups) { - for (Serializable::Message* m : g->messages) { - ::TextMessageNode* n = new ::TextMessageNode(); - n->m_pMessage = m ; - if (!n->m_pMessage->contactMethod) { - n->m_pMessage->contactMethod = const_cast<ContactMethod*>(cm); //TODO remove in 2016 - n->m_pMessage->authorSha1 = cm->sha1(); - - if (p->peers.isEmpty()) - addPeer(const_cast<Serializable::Peers*>(p), cm); + //Create the model + t->instantMessagingModel(); + + //Reconstruct the conversation + //TODO do it right, right now it flatten the graph + for (const Serializable::Peers* p : t->d_ptr->m_lAssociatedPeers) { + // TODO: for now assume the convo is with only 1 CM at a time + auto peerCM = p->peers.at(0)->m_pContactMethod; + + // get the latest timestamp to set last used + time_t lastUsed = 0; + for (const Serializable::Group* g : p->groups) { + for (Serializable::Message* m : g->messages) { + ::TextMessageNode* n = new ::TextMessageNode(); + n->m_pMessage = m ; + if (!n->m_pMessage->contactMethod) { + if (cm) { + n->m_pMessage->contactMethod = const_cast<ContactMethod*>(cm); //TODO remove in 2016 + n->m_pMessage->authorSha1 = cm->sha1(); + + if (p->peers.isEmpty()) + addPeer(const_cast<Serializable::Peers*>(p), cm); + } else { + if (p->m_hSha1.contains(n->m_pMessage->authorSha1)) { + n->m_pMessage->contactMethod = p->m_hSha1[n->m_pMessage->authorSha1]; + } else { + // message was outgoing and author sha1 was set to that of the sending account + n->m_pMessage->contactMethod = peerCM; + n->m_pMessage->authorSha1 = peerCM->sha1(); + } + } + } + n->m_pContactMethod = m->contactMethod; + t->d_ptr->m_pImModel->addRowBegin(); + t->d_ptr->m_lNodes << n; + t->d_ptr->m_pImModel->addRowEnd(); + + if (lastUsed < n->m_pMessage->timestamp) + lastUsed = n->m_pMessage->timestamp; } - n->m_pContactMethod = m->contactMethod; - t->d_ptr->m_pImModel->addRowBegin(); - t->d_ptr->m_lNodes << n; - t->d_ptr->m_pImModel->addRowEnd(); - } - } - } + } + + // update the timestamp of the CM + peerCM->setLastUsed(lastUsed); + } - return t; + return t; } void Media::TextRecordingPrivate::insertNewMessage(const QMap<QString,QString>& message, ContactMethod* cm, Media::Media::Direction direction) diff --git a/src/media/textrecording.h b/src/media/textrecording.h index fa4456f7bea2e209a265644393a88a3512cec75e..f0602e483608199ad9b237ad0bb58bcebe760edf 100644 --- a/src/media/textrecording.h +++ b/src/media/textrecording.h @@ -75,6 +75,7 @@ public: bool isEmpty ( ) const; bool hasMimeType ( const QString& mimeType ) const; QStringList mimeTypes ( ) const; + QVector<ContactMethod*> peers ( ) const; //Helper void setAllRead();