Input field fixes
* Message with multiple mentions are not broken in IRC. Fix #267 * Editing a message won't remove mentions anymore
This commit is contained in:
@@ -318,6 +318,11 @@ ToolBar {
|
|||||||
property real progress: 0
|
property real progress: 0
|
||||||
property bool autoAppeared: false
|
property bool autoAppeared: false
|
||||||
|
|
||||||
|
// store each user we autoComplete here, this will be helpful later to generate
|
||||||
|
// the matrix.to links.
|
||||||
|
// This use an hack to define: https://doc.qt.io/qt-5/qml-var.html#property-value-initialization-semantics
|
||||||
|
property var userAutocompleted: ({})
|
||||||
|
|
||||||
ChatDocumentHandler {
|
ChatDocumentHandler {
|
||||||
id: documentHandler
|
id: documentHandler
|
||||||
document: inputField.textDocument
|
document: inputField.textDocument
|
||||||
@@ -471,7 +476,7 @@ ToolBar {
|
|||||||
|
|
||||||
function postMessage() {
|
function postMessage() {
|
||||||
roomManager.actionsHandler.postMessage(inputField.text.trim(), attachmentPath,
|
roomManager.actionsHandler.postMessage(inputField.text.trim(), attachmentPath,
|
||||||
replyEventID, editEventId);
|
replyEventID, editEventId, inputField.userAutocompleted);
|
||||||
clearAttachment();
|
clearAttachment();
|
||||||
currentRoom.markAllMessagesAsRead();
|
currentRoom.markAllMessagesAsRead();
|
||||||
clear();
|
clear();
|
||||||
@@ -482,6 +487,10 @@ ToolBar {
|
|||||||
|
|
||||||
function autoComplete() {
|
function autoComplete() {
|
||||||
documentHandler.replaceAutoComplete(autoCompleteListView.currentItem.displayText)
|
documentHandler.replaceAutoComplete(autoCompleteListView.currentItem.displayText)
|
||||||
|
if (!autoCompleteListView.currentItem.isEmoji) {
|
||||||
|
inputField.userAutocompleted[autoCompleteListView.currentItem.displayText] = autoCompleteListView.currentItem.userId;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -573,15 +582,14 @@ ToolBar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function clear() {
|
function clear() {
|
||||||
inputField.clear()
|
inputField.clear();
|
||||||
|
inputField.userAutocompleted = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearEditReply() {
|
function clearEditReply() {
|
||||||
isReply = false;
|
isReply = false;
|
||||||
replyUser = null;
|
replyUser = null;
|
||||||
if (root.editEventId.length > 0) {
|
clear();
|
||||||
clear();
|
|
||||||
}
|
|
||||||
root.replyContent = "";
|
root.replyContent = "";
|
||||||
root.replyEventID = "";
|
root.replyEventID = "";
|
||||||
root.editEventId = "";
|
root.editEventId = "";
|
||||||
@@ -592,9 +600,26 @@ ToolBar {
|
|||||||
inputField.forceActiveFocus()
|
inputField.forceActiveFocus()
|
||||||
}
|
}
|
||||||
|
|
||||||
function edit(editContent, editEventId) {
|
function edit(editContent, editFormatedContent, editEventId) {
|
||||||
|
console.log("Editing ", editContent, "html:", editFormatedContent)
|
||||||
|
// Set the input field in edit mode
|
||||||
inputField.text = editContent;
|
inputField.text = editContent;
|
||||||
root.editEventId = editEventId
|
root.editEventId = editEventId
|
||||||
|
|
||||||
|
// clean autocompletion list
|
||||||
|
inputField.userAutocompleted = {};
|
||||||
|
|
||||||
|
// Fill autocompletion list with values extracted from message.
|
||||||
|
// We can't just iterate on every user in the list and try to
|
||||||
|
// find matching display name since some users have display name
|
||||||
|
// matching frequent words and this will marks too many words as
|
||||||
|
// mentions.
|
||||||
|
const regex = /<a href=\"https:\/\/matrix.to\/#\/(@[a-zA-Z09]*:[a-zA-Z09.]*)\">([^<]*)<\/a>/g;
|
||||||
|
|
||||||
|
let match;
|
||||||
|
while ((match = regex.exec(editFormatedContent.toString())) !== null) {
|
||||||
|
inputField.userAutocompleted[match[2]] = match[1];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeAll() {
|
function closeAll() {
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ RowLayout {
|
|||||||
QQC2.ToolTip.visible: hovered
|
QQC2.ToolTip.visible: hovered
|
||||||
visible: controlContainer.hovered && author.id === Controller.activeConnection.localUserId && (model.eventType === "emote" || model.eventType === "message")
|
visible: controlContainer.hovered && author.id === Controller.activeConnection.localUserId && (model.eventType === "emote" || model.eventType === "message")
|
||||||
icon.name: "document-edit"
|
icon.name: "document-edit"
|
||||||
onClicked: chatTextInput.edit(message, eventId)
|
onClicked: chatTextInput.edit(message, model.formattedBody, eventId)
|
||||||
}
|
}
|
||||||
QQC2.Button {
|
QQC2.Button {
|
||||||
QQC2.ToolTip.text: i18n("Reply")
|
QQC2.ToolTip.text: i18n("Reply")
|
||||||
|
|||||||
@@ -142,7 +142,6 @@ void ActionsHandler::joinRoom(const QString &alias)
|
|||||||
joinRoomJob->errorString()));
|
joinRoomJob->errorString()));
|
||||||
});
|
});
|
||||||
Quotient::JoinRoomJob::connect(joinRoomJob, &JoinRoomJob::success, [this, joinRoomJob] {
|
Quotient::JoinRoomJob::connect(joinRoomJob, &JoinRoomJob::success, [this, joinRoomJob] {
|
||||||
qDebug() << "joined" << joinRoomJob->roomId();
|
|
||||||
Q_EMIT roomJoined(joinRoomJob->roomId());
|
Q_EMIT roomJoined(joinRoomJob->roomId());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -159,15 +158,16 @@ void ActionsHandler::createRoom(const QString &name, const QString &topic)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ActionsHandler::postMessage(const QString &text,
|
void ActionsHandler::postMessage(const QString &text,
|
||||||
const QString &attachementPath, const QString &replyEventId, const QString &editEventId)
|
const QString &attachementPath, const QString &replyEventId, const QString &editEventId,
|
||||||
|
const QVariantMap &usernames)
|
||||||
{
|
{
|
||||||
QString rawText = text;
|
QString rawText = text;
|
||||||
QString cleanedText = text;
|
QString cleanedText = text;
|
||||||
|
|
||||||
for (const auto *user : m_room->users()) {
|
|
||||||
const auto displayName = user->displayname(m_room);
|
for (auto it = usernames.constBegin(); it != usernames.constEnd(); it++) {
|
||||||
cleanedText = cleanedText.replace(displayName,
|
cleanedText = cleanedText.replace(it.key(),
|
||||||
"[" + displayName + "](https://matrix.to/#/" + user->id() + ")");
|
"[" + it.key() + "](https://matrix.to/#/" + it.value().toString() + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attachementPath.length() > 0) {
|
if (attachementPath.length() > 0) {
|
||||||
@@ -328,5 +328,5 @@ void ActionsHandler::postMessage(const QString &text,
|
|||||||
cleanedText = cleanedText.remove(0, noticePrefix.length());
|
cleanedText = cleanedText.remove(0, noticePrefix.length());
|
||||||
messageEventType = RoomMessageEvent::MsgType::Notice;
|
messageEventType = RoomMessageEvent::MsgType::Notice;
|
||||||
}
|
}
|
||||||
m_room->postMessage(cleanedText, messageEventType, replyEventId, editEventId);
|
m_room->postMessage(rawText, cleanedText, messageEventType, replyEventId, editEventId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ public Q_SLOTS:
|
|||||||
///
|
///
|
||||||
/// This also interprets commands if any.
|
/// This also interprets commands if any.
|
||||||
void postMessage(const QString &text, const QString &attachementPath,
|
void postMessage(const QString &text, const QString &attachementPath,
|
||||||
const QString &replyEventId, const QString &editEventId);
|
const QString &replyEventId, const QString &editEventId, const QVariantMap &usernames);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Connection *m_connection = nullptr;
|
Connection *m_connection = nullptr;
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ QHash<int, QByteArray> MessageEventModel::roleNames() const
|
|||||||
roles[ShowSectionRole] = "showSection";
|
roles[ShowSectionRole] = "showSection";
|
||||||
roles[ReactionRole] = "reaction";
|
roles[ReactionRole] = "reaction";
|
||||||
roles[IsEditedRole] = "isEdited";
|
roles[IsEditedRole] = "isEdited";
|
||||||
|
roles[FormattedBodyRole] = "formattedBody";
|
||||||
return roles;
|
return roles;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -334,6 +335,16 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
|
|||||||
return m_currentRoom->eventToString(evt, Qt::RichText);
|
return m_currentRoom->eventToString(evt, Qt::RichText);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (role == FormattedBodyRole) {
|
||||||
|
if (auto e = eventCast<const RoomMessageEvent>(&evt)) {
|
||||||
|
if (e->hasTextContent() && e->mimeType().name() != "text/plain") {
|
||||||
|
return static_cast<const Quotient::EventContent::TextContent *>(e->content())->body;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
if (role == MessageRole) {
|
if (role == MessageRole) {
|
||||||
return m_currentRoom->eventToString(evt);
|
return m_currentRoom->eventToString(evt);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ public:
|
|||||||
LongOperationRole,
|
LongOperationRole,
|
||||||
AnnotationRole,
|
AnnotationRole,
|
||||||
UserMarkerRole,
|
UserMarkerRole,
|
||||||
|
FormattedBodyRole,
|
||||||
|
|
||||||
ReplyRole,
|
ReplyRole,
|
||||||
|
|
||||||
|
|||||||
@@ -538,12 +538,12 @@ QString msgTypeToString(MessageEventType msgType)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NeoChatRoom::postMessage(const QString &text, MessageEventType type, const QString &replyEventId, const QString &relateToEventId)
|
void NeoChatRoom::postMessage(const QString &rawText, const QString &text, MessageEventType type, const QString &replyEventId, const QString &relateToEventId)
|
||||||
{
|
{
|
||||||
const auto html = markdownToHTML(text);
|
const auto html = markdownToHTML(text);
|
||||||
QString cleanText(text);
|
QString cleanText(text);
|
||||||
cleanText.replace(QRegularExpression("\\[(.+)\\]\\(.+\\)"), "\\1");
|
cleanText.replace(QRegularExpression("\\[(.+)\\]\\(.+\\)"), "\\1");
|
||||||
postHtmlMessage(cleanText, html, type, replyEventId, relateToEventId);
|
postHtmlMessage(rawText, html, type, replyEventId, relateToEventId);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NeoChatRoom::postHtmlMessage(const QString &text, const QString &html, MessageEventType type, const QString &replyEventId, const QString &relateToEventId)
|
void NeoChatRoom::postHtmlMessage(const QString &text, const QString &html, MessageEventType type, const QString &replyEventId, const QString &relateToEventId)
|
||||||
|
|||||||
@@ -139,7 +139,9 @@ public Q_SLOTS:
|
|||||||
void acceptInvitation();
|
void acceptInvitation();
|
||||||
void forget();
|
void forget();
|
||||||
void sendTypingNotification(bool isTyping);
|
void sendTypingNotification(bool isTyping);
|
||||||
void postMessage(const QString &text, Quotient::MessageEventType type = Quotient::MessageEventType::Text, const QString &replyEventId = QString(), const QString &relateToEventId = QString());
|
/// @param rawText The text as it was typed.
|
||||||
|
/// @param cleanedText The text with link to the users.
|
||||||
|
void postMessage(const QString &rawText, const QString &cleanedText, Quotient::MessageEventType type = Quotient::MessageEventType::Text, const QString &replyEventId = QString(), const QString &relateToEventId = QString());
|
||||||
void postHtmlMessage(const QString &text, const QString &html, Quotient::MessageEventType type = Quotient::MessageEventType::Text, const QString &replyEventId = QString(), const QString &relateToEventId = QString());
|
void postHtmlMessage(const QString &text, const QString &html, Quotient::MessageEventType type = Quotient::MessageEventType::Text, const QString &replyEventId = QString(), const QString &relateToEventId = QString());
|
||||||
void changeAvatar(const QUrl &localFile);
|
void changeAvatar(const QUrl &localFile);
|
||||||
void addLocalAlias(const QString &alias);
|
void addLocalAlias(const QString &alias);
|
||||||
|
|||||||
Reference in New Issue
Block a user