feat: add a quick reply workflow using the Ctrl+Up arrow key
neochat now supports a quick reply shortcut, which helps to reply to the last event in a room.
This commit is contained in:
@@ -29,6 +29,7 @@ ToolBar {
|
|||||||
signal messageSent()
|
signal messageSent()
|
||||||
signal pasteImageTriggered()
|
signal pasteImageTriggered()
|
||||||
signal editLastUserMessage()
|
signal editLastUserMessage()
|
||||||
|
signal replyPreviousUserMessage()
|
||||||
|
|
||||||
property alias isCompleting: completionMenu.visible
|
property alias isCompleting: completionMenu.visible
|
||||||
|
|
||||||
@@ -142,7 +143,9 @@ ToolBar {
|
|||||||
switchRoomUp();
|
switchRoomUp();
|
||||||
} else if (event.key === Qt.Key_V && event.modifiers & Qt.ControlModifier) {
|
} else if (event.key === Qt.Key_V && event.modifiers & Qt.ControlModifier) {
|
||||||
chatBar.pasteImage();
|
chatBar.pasteImage();
|
||||||
} else if (event.key === Qt.Key_Up && !(event.modifiers & Qt.ControlModifier)) {
|
} else if (event.key === Qt.Key_Up && event.modifiers & Qt.ControlModifier) {
|
||||||
|
replyPreviousUserMessage();
|
||||||
|
} else if (event.key === Qt.Key_Up) {
|
||||||
editLastUserMessage();
|
editLastUserMessage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ Item {
|
|||||||
signal fancyEffectsReasonFound(string fancyEffect)
|
signal fancyEffectsReasonFound(string fancyEffect)
|
||||||
signal messageSent()
|
signal messageSent()
|
||||||
signal editLastUserMessage()
|
signal editLastUserMessage()
|
||||||
|
signal replyPreviousUserMessage()
|
||||||
|
|
||||||
Kirigami.Theme.colorSet: Kirigami.Theme.View
|
Kirigami.Theme.colorSet: Kirigami.Theme.View
|
||||||
|
|
||||||
@@ -157,6 +158,9 @@ Item {
|
|||||||
onEditLastUserMessage: {
|
onEditLastUserMessage: {
|
||||||
root.editLastUserMessage();
|
root.editLastUserMessage();
|
||||||
}
|
}
|
||||||
|
onReplyPreviousUserMessage: {
|
||||||
|
root.replyPreviousUserMessage();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkForFancyEffectsReason() {
|
function checkForFancyEffectsReason() {
|
||||||
|
|||||||
@@ -657,6 +657,12 @@ Kirigami.ScrollablePage {
|
|||||||
ChatBoxHelper.edit(targetMessage["body"], targetMessage["body"], targetMessage["event_id"]);
|
ChatBoxHelper.edit(targetMessage["body"], targetMessage["body"], targetMessage["event_id"]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
onReplyPreviousUserMessage: {
|
||||||
|
const replyResponse = messageEventModel.getLatestMessageFromIndex(0);
|
||||||
|
if (replyResponse && replyResponse["event_id"]) {
|
||||||
|
ChatBoxHelper.replyToMessage(replyResponse["event_id"], replyResponse["event"], replyResponse["sender_id"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
background: FancyEffectsContainer {
|
background: FancyEffectsContainer {
|
||||||
|
|||||||
@@ -672,3 +672,43 @@ QVariant MessageEventModel::getLastLocalUserMessageEventId()
|
|||||||
}
|
}
|
||||||
return targetMessage;
|
return targetMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVariant MessageEventModel::getLatestMessageFromIndex(const int baseline)
|
||||||
|
{
|
||||||
|
QVariantMap replyResponse;
|
||||||
|
const auto &timelineBottom = m_currentRoom->messageEvents().rbegin() + baseline;
|
||||||
|
|
||||||
|
// set a cap limit of baseline + 35 messages, to prevent loading a lot of messages
|
||||||
|
// in rooms where the user has not sent many messages
|
||||||
|
const auto limit = timelineBottom + std::min(baseline + 35, m_currentRoom->timelineSize());
|
||||||
|
|
||||||
|
for (auto it = timelineBottom; it != limit; ++it) {
|
||||||
|
auto evt = it->event();
|
||||||
|
auto e = eventCast<const RoomMessageEvent>(evt);
|
||||||
|
|
||||||
|
auto content = (*it)->contentJson();
|
||||||
|
|
||||||
|
if (content.contains("m.relates_to")) {
|
||||||
|
auto relatedContent = content["m.relates_to"].toObject();
|
||||||
|
|
||||||
|
if (!relatedContent.contains("m.in_reply_to")) {
|
||||||
|
// the message has been edited once
|
||||||
|
// so we have to return the id of the related' message instead
|
||||||
|
replyResponse.insert("event_id", relatedContent["event_id"].toString());
|
||||||
|
replyResponse.insert("event", content["m.formatted_body"].toString());
|
||||||
|
replyResponse.insert("sender_id", QVariant::fromValue(m_currentRoom->getUser((*it)->senderId())));
|
||||||
|
replyResponse.insert("at", -it->index());
|
||||||
|
return replyResponse;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e->msgtype() != MessageEventType::Unknown) {
|
||||||
|
replyResponse.insert("event_id", (*it)->id());
|
||||||
|
replyResponse.insert("event", content["body"].toString());
|
||||||
|
replyResponse.insert("sender_id", QVariant::fromValue(m_currentRoom->getUser((*it)->senderId())));
|
||||||
|
replyResponse.insert("at", -it->index());
|
||||||
|
return replyResponse;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return replyResponse;
|
||||||
|
}
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ public:
|
|||||||
|
|
||||||
Q_INVOKABLE [[nodiscard]] int eventIDToIndex(const QString &eventID) const;
|
Q_INVOKABLE [[nodiscard]] int eventIDToIndex(const QString &eventID) const;
|
||||||
Q_INVOKABLE [[nodiscard]] QVariant getLastLocalUserMessageEventId();
|
Q_INVOKABLE [[nodiscard]] QVariant getLastLocalUserMessageEventId();
|
||||||
|
Q_INVOKABLE [[nodiscard]] QVariant getLatestMessageFromIndex(const int baseline);
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
int refreshEvent(const QString &eventId);
|
int refreshEvent(const QString &eventId);
|
||||||
|
|||||||
@@ -265,6 +265,17 @@ QVariantList NeoChatRoom::getUsers(const QString &keyword) const
|
|||||||
return matchedList;
|
return matchedList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVariantMap NeoChatRoom::getUser(const QString& userID) const
|
||||||
|
{
|
||||||
|
NeoChatUser user(userID, connection());
|
||||||
|
return QVariantMap {
|
||||||
|
{ QStringLiteral("id"), user.id() },
|
||||||
|
{ QStringLiteral("displayName"), user.displayname(this) },
|
||||||
|
{ QStringLiteral("avatarMediaId"), user.avatarMediaId(this) },
|
||||||
|
{ QStringLiteral("color"), user.color() }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
QUrl NeoChatRoom::urlToMxcUrl(const QUrl &mxcUrl)
|
QUrl NeoChatRoom::urlToMxcUrl(const QUrl &mxcUrl)
|
||||||
{
|
{
|
||||||
return DownloadFileJob::makeRequestUrl(connection()->homeserver(), mxcUrl);
|
return DownloadFileJob::makeRequestUrl(connection()->homeserver(), mxcUrl);
|
||||||
|
|||||||
@@ -92,6 +92,7 @@ public:
|
|||||||
Q_INVOKABLE void saveViewport(int topIndex, int bottomIndex);
|
Q_INVOKABLE void saveViewport(int topIndex, int bottomIndex);
|
||||||
|
|
||||||
Q_INVOKABLE [[nodiscard]] QVariantList getUsers(const QString &keyword) const;
|
Q_INVOKABLE [[nodiscard]] QVariantList getUsers(const QString &keyword) const;
|
||||||
|
Q_INVOKABLE [[nodiscard]] QVariantMap getUser(const QString &userID) const;
|
||||||
|
|
||||||
Q_INVOKABLE QUrl urlToMxcUrl(const QUrl &mxcUrl);
|
Q_INVOKABLE QUrl urlToMxcUrl(const QUrl &mxcUrl);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user