fix #LINQT-11899 text in messages disappearing (compute encoding to rich format only once for each message instead of doing it everytime something changes in the list)
This commit is contained in:
parent
836d0b1da3
commit
be531b5e9f
6 changed files with 120 additions and 8 deletions
|
|
@ -63,6 +63,8 @@ ChatMessageContentCore::ChatMessageContentCore(const std::shared_ptr<linphone::C
|
||||||
mFileDuration = content->getFileDuration();
|
mFileDuration = content->getFileDuration();
|
||||||
mFileOffset = 0;
|
mFileOffset = 0;
|
||||||
mUtf8Text = Utils::coreStringToAppString(content->getUtf8Text());
|
mUtf8Text = Utils::coreStringToAppString(content->getUtf8Text());
|
||||||
|
auto chatRoom = chatMessageModel ? chatMessageModel->getMonitor()->getChatRoom() : nullptr;
|
||||||
|
mRichFormatText = ToolModel::encodeTextToQmlRichFormat(mUtf8Text, {}, chatRoom);
|
||||||
mWasDownloaded = !mFilePath.isEmpty() && QFileInfo(mFilePath).isFile();
|
mWasDownloaded = !mFilePath.isEmpty() && QFileInfo(mFilePath).isFile();
|
||||||
mThumbnail = mFilePath.isEmpty()
|
mThumbnail = mFilePath.isEmpty()
|
||||||
? QString()
|
? QString()
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ class ChatMessageContentCore : public QObject, public AbstractObject {
|
||||||
Q_PROPERTY(bool wasDownloaded READ wasDownloaded WRITE setWasDownloaded NOTIFY wasDownloadedChanged)
|
Q_PROPERTY(bool wasDownloaded READ wasDownloaded WRITE setWasDownloaded NOTIFY wasDownloadedChanged)
|
||||||
Q_PROPERTY(QString filePath READ getFilePath WRITE setFilePath NOTIFY filePathChanged)
|
Q_PROPERTY(QString filePath READ getFilePath WRITE setFilePath NOTIFY filePathChanged)
|
||||||
Q_PROPERTY(QString utf8Text READ getUtf8Text CONSTANT)
|
Q_PROPERTY(QString utf8Text READ getUtf8Text CONSTANT)
|
||||||
|
Q_PROPERTY(QString richFormatText MEMBER mRichFormatText CONSTANT)
|
||||||
Q_PROPERTY(bool isFile READ isFile WRITE setIsFile NOTIFY isFileChanged)
|
Q_PROPERTY(bool isFile READ isFile WRITE setIsFile NOTIFY isFileChanged)
|
||||||
Q_PROPERTY(bool isFileEncrypted READ isFileEncrypted WRITE setIsFileEncrypted NOTIFY isFileEncryptedChanged)
|
Q_PROPERTY(bool isFileEncrypted READ isFileEncrypted WRITE setIsFileEncrypted NOTIFY isFileEncryptedChanged)
|
||||||
Q_PROPERTY(bool isFileTransfer READ isFileTransfer WRITE setIsFileTransfer NOTIFY isFileTransferChanged)
|
Q_PROPERTY(bool isFileTransfer READ isFileTransfer WRITE setIsFileTransfer NOTIFY isFileTransferChanged)
|
||||||
|
|
@ -122,6 +123,7 @@ private:
|
||||||
int mFileDuration;
|
int mFileDuration;
|
||||||
QString mThumbnail;
|
QString mThumbnail;
|
||||||
QString mUtf8Text;
|
QString mUtf8Text;
|
||||||
|
QString mRichFormatText;
|
||||||
QString mFilePath;
|
QString mFilePath;
|
||||||
QString mName;
|
QString mName;
|
||||||
quint64 mFileSize;
|
quint64 mFileSize;
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@
|
||||||
#include "core/path/Paths.hpp"
|
#include "core/path/Paths.hpp"
|
||||||
#include "model/core/CoreModel.hpp"
|
#include "model/core/CoreModel.hpp"
|
||||||
#include "model/friend/FriendsManager.hpp"
|
#include "model/friend/FriendsManager.hpp"
|
||||||
|
#include "tool/UriTools.hpp"
|
||||||
#include "tool/Utils.hpp"
|
#include "tool/Utils.hpp"
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QDirIterator>
|
#include <QDirIterator>
|
||||||
|
|
@ -117,6 +118,108 @@ QString ToolModel::getDisplayName(QString address) {
|
||||||
return nameSplitted.join(" ");
|
return nameSplitted.join(" ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString ToolModel::encodeTextToQmlRichFormat(const QString &text,
|
||||||
|
const QVariantMap &options,
|
||||||
|
std::shared_ptr<linphone::ChatRoom> chatRoom) {
|
||||||
|
QStringList formattedText;
|
||||||
|
bool lastWasUrl = false;
|
||||||
|
auto primaryColor = QColor::fromString("#4AA8FF");
|
||||||
|
|
||||||
|
if (options.contains("noLink") && options["noLink"].toBool()) {
|
||||||
|
formattedText.append(Utils::encodeEmojiToQmlRichFormat(text));
|
||||||
|
} else {
|
||||||
|
|
||||||
|
auto iriParsed = UriTools::parseIri(text);
|
||||||
|
|
||||||
|
for (int i = 0; i < iriParsed.size(); ++i) {
|
||||||
|
QString iri = iriParsed[i]
|
||||||
|
.second.replace('&', "&")
|
||||||
|
.replace('<', "\u2063<")
|
||||||
|
.replace('>', "\u2063>")
|
||||||
|
.replace('"', """)
|
||||||
|
.replace('\'', "'");
|
||||||
|
if (!iriParsed[i].first) {
|
||||||
|
if (lastWasUrl) {
|
||||||
|
lastWasUrl = false;
|
||||||
|
if (iri.front() != ' ') iri.push_front(' ');
|
||||||
|
}
|
||||||
|
formattedText.append(Utils::encodeEmojiToQmlRichFormat(iri));
|
||||||
|
} else {
|
||||||
|
QString uri =
|
||||||
|
iriParsed[i].second.left(3) == "www" ? "http://" + iriParsed[i].second : iriParsed[i].second;
|
||||||
|
/* TODO : preview from link
|
||||||
|
int extIndex = iriParsed[i].second.lastIndexOf('.');
|
||||||
|
QString ext;
|
||||||
|
if( extIndex >= 0)
|
||||||
|
ext = iriParsed[i].second.mid(extIndex+1).toUpper();
|
||||||
|
if(imageFormat.contains(ext.toLatin1())){// imagesHeight is not used because of bugs on display
|
||||||
|
(blank image if set without width) images += "<a href=\"" + uri + "\"><img" + (
|
||||||
|
options.contains("imagesWidth") ? QString(" width='") + options["imagesWidth"].toString() + "'" : ""
|
||||||
|
) + (
|
||||||
|
options.contains("imagesWidth")
|
||||||
|
? QString(" height='auto'")
|
||||||
|
: ""
|
||||||
|
) + " src=\"" + iriParsed[i].second + "\" />"+uri+"</a>";
|
||||||
|
}else{
|
||||||
|
*/
|
||||||
|
formattedText.append("<a style=\"color:" + primaryColor.name() + ";\" href=\"" + uri + "\">" + iri +
|
||||||
|
"</a>");
|
||||||
|
lastWasUrl = true;
|
||||||
|
/*}*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (lastWasUrl && formattedText.last().back() != ' ') {
|
||||||
|
formattedText.push_back(" ");
|
||||||
|
}
|
||||||
|
if (chatRoom) {
|
||||||
|
auto participants = chatRoom->getParticipants();
|
||||||
|
auto mentionsParsed = UriTools::parseMention(formattedText.join(""));
|
||||||
|
formattedText.clear();
|
||||||
|
|
||||||
|
for (int i = 0; i < mentionsParsed.size(); ++i) {
|
||||||
|
QString mention = mentionsParsed[i].second;
|
||||||
|
|
||||||
|
if (mentionsParsed[i].first) {
|
||||||
|
QString mentions = mentionsParsed[i].second;
|
||||||
|
QStringList finalMentions;
|
||||||
|
QStringList parts = mentions.split(" ");
|
||||||
|
for (auto part : parts) {
|
||||||
|
if (part.startsWith("@")) { // mention
|
||||||
|
QString username = part;
|
||||||
|
username.removeFirst();
|
||||||
|
auto it = std::find_if(participants.begin(), participants.end(),
|
||||||
|
[username](std::shared_ptr<linphone::Participant> p) {
|
||||||
|
return p->getAddress() && username == p->getAddress()->getUsername();
|
||||||
|
});
|
||||||
|
if (it != participants.end()) {
|
||||||
|
auto foundParticipant = *it;
|
||||||
|
// participants.at(std::distance(participants.begin(), it));
|
||||||
|
auto address = foundParticipant->getAddress()->clone();
|
||||||
|
auto isFriend = findFriendByAddress(address);
|
||||||
|
address->clean();
|
||||||
|
auto addressString = Utils::coreStringToAppString(address->asStringUriOnly());
|
||||||
|
if (isFriend)
|
||||||
|
part = "@" + Utils::coreStringToAppString(isFriend->getAddress()->getDisplayName());
|
||||||
|
QString participantLink = "<a style=\"color:" + primaryColor.name() +
|
||||||
|
";\" href=\"mention:" + addressString + "\">" + part + "</a>";
|
||||||
|
finalMentions.append(participantLink);
|
||||||
|
} else {
|
||||||
|
finalMentions.append(part);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
finalMentions.append(part);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
formattedText.push_back(finalMentions.join(" "));
|
||||||
|
} else {
|
||||||
|
formattedText.push_back(mentionsParsed[i].second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "<p style=\"white-space:pre-wrap;\">" + formattedText.join("");
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<linphone::Friend> ToolModel::findFriendByAddress(const QString &address) {
|
std::shared_ptr<linphone::Friend> ToolModel::findFriendByAddress(const QString &address) {
|
||||||
auto defaultFriendList = CoreModel::getInstance()->getCore()->getDefaultFriendList();
|
auto defaultFriendList = CoreModel::getInstance()->getCore()->getDefaultFriendList();
|
||||||
if (!defaultFriendList) return nullptr;
|
if (!defaultFriendList) return nullptr;
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,10 @@ public:
|
||||||
static QString getDisplayName(const std::shared_ptr<linphone::Address> &address);
|
static QString getDisplayName(const std::shared_ptr<linphone::Address> &address);
|
||||||
static QString getDisplayName(QString address);
|
static QString getDisplayName(QString address);
|
||||||
|
|
||||||
|
static QString encodeTextToQmlRichFormat(const QString &text,
|
||||||
|
const QVariantMap &options,
|
||||||
|
std::shared_ptr<linphone::ChatRoom> chatRoom);
|
||||||
|
|
||||||
static std::shared_ptr<linphone::Friend> findFriendByAddress(const QString &address);
|
static std::shared_ptr<linphone::Friend> findFriendByAddress(const QString &address);
|
||||||
static std::shared_ptr<linphone::Friend> findFriendByAddress(std::shared_ptr<linphone::Address> linphoneAddr);
|
static std::shared_ptr<linphone::Friend> findFriendByAddress(std::shared_ptr<linphone::Address> linphoneAddr);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,10 @@ ListView {
|
||||||
initialDisplayItems: 10
|
initialDisplayItems: 10
|
||||||
onEventInserted: (index, gui) => {
|
onEventInserted: (index, gui) => {
|
||||||
if (!mainItem.visible) return
|
if (!mainItem.visible) return
|
||||||
if(mainItem.lastItemVisible) mainItem.positionViewAtIndex(index, ListView.Beginning)
|
if(mainItem.lastItemVisible) {
|
||||||
|
mainItem.positionViewAtIndex(index, ListView.Beginning)
|
||||||
|
markIndexAsRead(index)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Component.onCompleted: loading = true
|
Component.onCompleted: loading = true
|
||||||
onListAboutToBeReset: loading = true
|
onListAboutToBeReset: loading = true
|
||||||
|
|
@ -239,6 +242,7 @@ ListView {
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
if (index === 0) mainItem.lastItemVisible = isFullyVisible
|
if (index === 0) mainItem.lastItemVisible = isFullyVisible
|
||||||
}
|
}
|
||||||
|
onYChanged: if (index === 0) mainItem.lastItemVisible = isFullyVisible
|
||||||
chat: mainItem.chat
|
chat: mainItem.chat
|
||||||
searchedTextPart: mainItem.filterText
|
searchedTextPart: mainItem.filterText
|
||||||
maxWidth: Math.round(mainItem.width * (3/4))
|
maxWidth: Math.round(mainItem.width * (3/4))
|
||||||
|
|
|
||||||
|
|
@ -26,13 +26,10 @@ TextEdit {
|
||||||
readOnly: true
|
readOnly: true
|
||||||
selectByMouse: true
|
selectByMouse: true
|
||||||
|
|
||||||
property var encodeTextObj: visible ? UtilsCpp.encodeTextToQmlRichFormat(contentGui.core.utf8Text, {}, mainItem.chatGui)
|
text: searchedTextPart !== ""
|
||||||
: ''
|
? UtilsCpp.boldTextPart(contentGui.core.richFormatText, searchedTextPart)
|
||||||
text: encodeTextObj
|
: contentGui.core.richFormatText
|
||||||
&& (searchedTextPart !== ""
|
|
||||||
? UtilsCpp.boldTextPart(encodeTextObj.value, searchedTextPart)
|
|
||||||
: encodeTextObj.value)
|
|
||||||
|| ""
|
|
||||||
textFormat: Text.RichText // To supports links and imgs.
|
textFormat: Text.RichText // To supports links and imgs.
|
||||||
wrapMode: TextEdit.Wrap
|
wrapMode: TextEdit.Wrap
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue