Basic text input in qml
This commit is contained in:
parent
7a74b86340
commit
0bb4885632
@ -58,9 +58,14 @@ Rectangle {
|
|||||||
onSelectionStartChanged: TimelineManager.timeline.input.updateState(selectionStart, selectionEnd, cursorPosition, text)
|
onSelectionStartChanged: TimelineManager.timeline.input.updateState(selectionStart, selectionEnd, cursorPosition, text)
|
||||||
onSelectionEndChanged: TimelineManager.timeline.input.updateState(selectionStart, selectionEnd, cursorPosition, text)
|
onSelectionEndChanged: TimelineManager.timeline.input.updateState(selectionStart, selectionEnd, cursorPosition, text)
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: TimelineManager.timeline.input
|
||||||
|
function onInsertText(text_) { textArea.insert(textArea.cursorPosition, text_); }
|
||||||
|
}
|
||||||
|
|
||||||
Keys.onPressed: {
|
Keys.onPressed: {
|
||||||
if (event.matches(StandardKey.Paste)) {
|
if (event.matches(StandardKey.Paste)) {
|
||||||
TimelineManager.timeline.input.paste(false) || textArea.paste()
|
TimelineManager.timeline.input.paste(false)
|
||||||
event.accepted = true
|
event.accepted = true
|
||||||
}
|
}
|
||||||
else if (event.matches(StandardKey.InsertParagraphSeparator)) {
|
else if (event.matches(StandardKey.InsertParagraphSeparator)) {
|
||||||
@ -75,7 +80,7 @@ Rectangle {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
acceptedButtons: Qt.MiddleButton
|
acceptedButtons: Qt.MiddleButton
|
||||||
cursorShape: Qt.IBeamCursor
|
cursorShape: Qt.IBeamCursor
|
||||||
onClicked: TimelineManager.timeline.input.paste(true) || textArea.paste()
|
onClicked: TimelineManager.timeline.input.paste(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
|
@ -160,15 +160,6 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
|
|||||||
trySync();
|
trySync();
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(text_input_,
|
|
||||||
&TextInputWidget::clearRoomTimeline,
|
|
||||||
view_manager_,
|
|
||||||
&TimelineViewManager::clearCurrentRoomTimeline);
|
|
||||||
|
|
||||||
connect(text_input_, &TextInputWidget::rotateMegolmSession, this, [this]() {
|
|
||||||
cache::dropOutboundMegolmSession(current_room_.toStdString());
|
|
||||||
});
|
|
||||||
|
|
||||||
connect(
|
connect(
|
||||||
new QShortcut(QKeySequence("Ctrl+Down"), this), &QShortcut::activated, this, [this]() {
|
new QShortcut(QKeySequence("Ctrl+Down"), this), &QShortcut::activated, this, [this]() {
|
||||||
if (isVisible())
|
if (isVisible())
|
||||||
@ -277,45 +268,6 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
|
|||||||
this,
|
this,
|
||||||
SIGNAL(unreadMessages(int)));
|
SIGNAL(unreadMessages(int)));
|
||||||
|
|
||||||
connect(text_input_,
|
|
||||||
&TextInputWidget::sendTextMessage,
|
|
||||||
view_manager_,
|
|
||||||
&TimelineViewManager::queueTextMessage);
|
|
||||||
|
|
||||||
connect(text_input_,
|
|
||||||
&TextInputWidget::sendEmoteMessage,
|
|
||||||
view_manager_,
|
|
||||||
&TimelineViewManager::queueEmoteMessage);
|
|
||||||
|
|
||||||
connect(text_input_, &TextInputWidget::sendJoinRoomRequest, this, &ChatPage::joinRoom);
|
|
||||||
|
|
||||||
// invites and bans via quick command
|
|
||||||
connect(text_input_, &TextInputWidget::sendInviteRoomRequest, this, &ChatPage::inviteUser);
|
|
||||||
connect(text_input_, &TextInputWidget::sendKickRoomRequest, this, &ChatPage::kickUser);
|
|
||||||
connect(text_input_, &TextInputWidget::sendBanRoomRequest, this, &ChatPage::banUser);
|
|
||||||
connect(text_input_, &TextInputWidget::sendUnbanRoomRequest, this, &ChatPage::unbanUser);
|
|
||||||
|
|
||||||
connect(
|
|
||||||
text_input_, &TextInputWidget::changeRoomNick, this, [this](const QString &displayName) {
|
|
||||||
mtx::events::state::Member member;
|
|
||||||
member.display_name = displayName.toStdString();
|
|
||||||
member.avatar_url =
|
|
||||||
cache::avatarUrl(currentRoom(),
|
|
||||||
QString::fromStdString(http::client()->user_id().to_string()))
|
|
||||||
.toStdString();
|
|
||||||
member.membership = mtx::events::state::Membership::Join;
|
|
||||||
|
|
||||||
http::client()->send_state_event(
|
|
||||||
currentRoom().toStdString(),
|
|
||||||
http::client()->user_id().to_string(),
|
|
||||||
member,
|
|
||||||
[](mtx::responses::EventId, mtx::http::RequestErr err) {
|
|
||||||
if (err)
|
|
||||||
nhlog::net()->error("Failed to set room displayname: {}",
|
|
||||||
err->matrix_error.error);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
connect(
|
connect(
|
||||||
text_input_,
|
text_input_,
|
||||||
&TextInputWidget::uploadMedia,
|
&TextInputWidget::uploadMedia,
|
||||||
|
@ -109,6 +109,7 @@ public:
|
|||||||
public slots:
|
public slots:
|
||||||
void leaveRoom(const QString &room_id);
|
void leaveRoom(const QString &room_id);
|
||||||
void createRoom(const mtx::requests::CreateRoom &req);
|
void createRoom(const mtx::requests::CreateRoom &req);
|
||||||
|
void joinRoom(const QString &room);
|
||||||
|
|
||||||
void inviteUser(QString userid, QString reason);
|
void inviteUser(QString userid, QString reason);
|
||||||
void kickUser(QString userid, QString reason);
|
void kickUser(QString userid, QString reason);
|
||||||
@ -200,7 +201,6 @@ private slots:
|
|||||||
void removeRoom(const QString &room_id);
|
void removeRoom(const QString &room_id);
|
||||||
void dropToLoginPage(const QString &msg);
|
void dropToLoginPage(const QString &msg);
|
||||||
|
|
||||||
void joinRoom(const QString &room);
|
|
||||||
void sendTypingNotifications();
|
void sendTypingNotifications();
|
||||||
void handleSyncResponse(const mtx::responses::Sync &res);
|
void handleSyncResponse(const mtx::responses::Sync &res);
|
||||||
|
|
||||||
|
@ -486,36 +486,7 @@ FilteredTextEdit::minimumSizeHint() const
|
|||||||
|
|
||||||
void
|
void
|
||||||
FilteredTextEdit::submit()
|
FilteredTextEdit::submit()
|
||||||
{
|
{}
|
||||||
if (toPlainText().trimmed().isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (true_history_.size() == INPUT_HISTORY_SIZE)
|
|
||||||
true_history_.pop_back();
|
|
||||||
true_history_.push_front(toPlainText());
|
|
||||||
working_history_ = true_history_;
|
|
||||||
working_history_.push_front("");
|
|
||||||
history_index_ = 0;
|
|
||||||
|
|
||||||
QString text = toPlainText();
|
|
||||||
|
|
||||||
if (text.startsWith('/')) {
|
|
||||||
int command_end = text.indexOf(' ');
|
|
||||||
if (command_end == -1)
|
|
||||||
command_end = text.size();
|
|
||||||
auto name = text.mid(1, command_end - 1);
|
|
||||||
auto args = text.mid(command_end + 1);
|
|
||||||
if (name.isEmpty() || name == "/") {
|
|
||||||
message(args);
|
|
||||||
} else {
|
|
||||||
command(name, args);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
message(std::move(text));
|
|
||||||
}
|
|
||||||
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
FilteredTextEdit::textChanged()
|
FilteredTextEdit::textChanged()
|
||||||
@ -653,8 +624,6 @@ TextInputWidget::TextInputWidget(QWidget *parent)
|
|||||||
#endif
|
#endif
|
||||||
connect(sendMessageBtn_, &FlatButton::clicked, input_, &FilteredTextEdit::submit);
|
connect(sendMessageBtn_, &FlatButton::clicked, input_, &FilteredTextEdit::submit);
|
||||||
connect(sendFileBtn_, SIGNAL(clicked()), this, SLOT(openFileSelection()));
|
connect(sendFileBtn_, SIGNAL(clicked()), this, SLOT(openFileSelection()));
|
||||||
connect(input_, &FilteredTextEdit::message, this, &TextInputWidget::sendTextMessage);
|
|
||||||
connect(input_, &FilteredTextEdit::command, this, &TextInputWidget::command);
|
|
||||||
connect(input_, &FilteredTextEdit::media, this, &TextInputWidget::uploadMedia);
|
connect(input_, &FilteredTextEdit::media, this, &TextInputWidget::uploadMedia);
|
||||||
connect(emojiBtn_,
|
connect(emojiBtn_,
|
||||||
SIGNAL(emojiSelected(const QString &)),
|
SIGNAL(emojiSelected(const QString &)),
|
||||||
@ -685,38 +654,6 @@ TextInputWidget::addSelectedEmoji(const QString &emoji)
|
|||||||
input_->show();
|
input_->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
TextInputWidget::command(QString command, QString args)
|
|
||||||
{
|
|
||||||
if (command == "me") {
|
|
||||||
emit sendEmoteMessage(args);
|
|
||||||
} else if (command == "join") {
|
|
||||||
emit sendJoinRoomRequest(args);
|
|
||||||
} else if (command == "invite") {
|
|
||||||
emit sendInviteRoomRequest(args.section(' ', 0, 0), args.section(' ', 1, -1));
|
|
||||||
} else if (command == "kick") {
|
|
||||||
emit sendKickRoomRequest(args.section(' ', 0, 0), args.section(' ', 1, -1));
|
|
||||||
} else if (command == "ban") {
|
|
||||||
emit sendBanRoomRequest(args.section(' ', 0, 0), args.section(' ', 1, -1));
|
|
||||||
} else if (command == "unban") {
|
|
||||||
emit sendUnbanRoomRequest(args.section(' ', 0, 0), args.section(' ', 1, -1));
|
|
||||||
} else if (command == "roomnick") {
|
|
||||||
emit changeRoomNick(args);
|
|
||||||
} else if (command == "shrug") {
|
|
||||||
emit sendTextMessage("¯\\_(ツ)_/¯" + (args.isEmpty() ? "" : " " + args));
|
|
||||||
} else if (command == "fliptable") {
|
|
||||||
emit sendTextMessage("(╯°□°)╯︵ ┻━┻");
|
|
||||||
} else if (command == "unfliptable") {
|
|
||||||
emit sendTextMessage(" ┯━┯╭( º _ º╭)");
|
|
||||||
} else if (command == "sovietflip") {
|
|
||||||
emit sendTextMessage("ノ┬─┬ノ ︵ ( \\o°o)\\");
|
|
||||||
} else if (command == "clear-timeline") {
|
|
||||||
emit clearRoomTimeline();
|
|
||||||
} else if (command == "rotate-megolm-session") {
|
|
||||||
emit rotateMegolmSession();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
TextInputWidget::openFileSelection()
|
TextInputWidget::openFileSelection()
|
||||||
{
|
{
|
||||||
|
@ -170,9 +170,6 @@ private slots:
|
|||||||
void addSelectedEmoji(const QString &emoji);
|
void addSelectedEmoji(const QString &emoji);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void sendTextMessage(const QString &msg);
|
|
||||||
void sendEmoteMessage(QString msg);
|
|
||||||
void clearRoomTimeline();
|
|
||||||
void heightChanged(int height);
|
void heightChanged(int height);
|
||||||
|
|
||||||
void uploadMedia(const QSharedPointer<QIODevice> data,
|
void uploadMedia(const QSharedPointer<QIODevice> data,
|
||||||
@ -186,7 +183,6 @@ signals:
|
|||||||
void sendBanRoomRequest(const QString &userid, const QString &reason);
|
void sendBanRoomRequest(const QString &userid, const QString &reason);
|
||||||
void sendUnbanRoomRequest(const QString &userid, const QString &reason);
|
void sendUnbanRoomRequest(const QString &userid, const QString &reason);
|
||||||
void changeRoomNick(const QString &displayname);
|
void changeRoomNick(const QString &displayname);
|
||||||
void rotateMegolmSession();
|
|
||||||
|
|
||||||
void startedTyping();
|
void startedTyping();
|
||||||
void stoppedTyping();
|
void stoppedTyping();
|
||||||
@ -197,7 +193,6 @@ protected:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void showUploadSpinner();
|
void showUploadSpinner();
|
||||||
void command(QString name, QString args);
|
|
||||||
|
|
||||||
QHBoxLayout *topLayout_;
|
QHBoxLayout *topLayout_;
|
||||||
FilteredTextEdit *input_;
|
FilteredTextEdit *input_;
|
||||||
|
@ -4,9 +4,19 @@
|
|||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
#include <QMimeData>
|
#include <QMimeData>
|
||||||
|
|
||||||
#include "Logging.h"
|
#include <mtx/responses/common.hpp>
|
||||||
|
|
||||||
bool
|
#include "Cache.h"
|
||||||
|
#include "ChatPage.h"
|
||||||
|
#include "Logging.h"
|
||||||
|
#include "MatrixClient.h"
|
||||||
|
#include "TimelineModel.h"
|
||||||
|
#include "UserSettingsPage.h"
|
||||||
|
#include "Utils.h"
|
||||||
|
|
||||||
|
static constexpr size_t INPUT_HISTORY_SIZE = 10;
|
||||||
|
|
||||||
|
void
|
||||||
InputBar::paste(bool fromMouse)
|
InputBar::paste(bool fromMouse)
|
||||||
{
|
{
|
||||||
const QMimeData *md = nullptr;
|
const QMimeData *md = nullptr;
|
||||||
@ -20,13 +30,13 @@ InputBar::paste(bool fromMouse)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!md)
|
if (!md)
|
||||||
return false;
|
return;
|
||||||
|
|
||||||
if (md->hasImage()) {
|
if (md->hasImage()) {
|
||||||
return true;
|
} else if (md->hasText()) {
|
||||||
|
emit insertText(md->text());
|
||||||
} else {
|
} else {
|
||||||
nhlog::ui()->debug("formats: {}", md->formats().join(", ").toStdString());
|
nhlog::ui()->debug("formats: {}", md->formats().join(", ").toStdString());
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,5 +52,147 @@ InputBar::updateState(int selectionStart_, int selectionEnd_, int cursorPosition
|
|||||||
void
|
void
|
||||||
InputBar::send()
|
InputBar::send()
|
||||||
{
|
{
|
||||||
|
if (text.trimmed().isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (history_.size() == INPUT_HISTORY_SIZE)
|
||||||
|
history_.pop_back();
|
||||||
|
history_.push_front(text);
|
||||||
|
history_index_ = 0;
|
||||||
|
|
||||||
|
if (text.startsWith('/')) {
|
||||||
|
int command_end = text.indexOf(' ');
|
||||||
|
if (command_end == -1)
|
||||||
|
command_end = text.size();
|
||||||
|
auto name = text.mid(1, command_end - 1);
|
||||||
|
auto args = text.mid(command_end + 1);
|
||||||
|
if (name.isEmpty() || name == "/") {
|
||||||
|
message(args);
|
||||||
|
} else {
|
||||||
|
command(name, args);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
message(text);
|
||||||
|
}
|
||||||
|
|
||||||
nhlog::ui()->debug("Send: {}", text.toStdString());
|
nhlog::ui()->debug("Send: {}", text.toStdString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
InputBar::message(QString msg)
|
||||||
|
{
|
||||||
|
mtx::events::msg::Text text = {};
|
||||||
|
text.body = msg.trimmed().toStdString();
|
||||||
|
|
||||||
|
if (ChatPage::instance()->userSettings()->markdown()) {
|
||||||
|
text.formatted_body = utils::markdownToHtml(msg).toStdString();
|
||||||
|
|
||||||
|
// Don't send formatted_body, when we don't need to
|
||||||
|
if (text.formatted_body.find("<") == std::string::npos)
|
||||||
|
text.formatted_body = "";
|
||||||
|
else
|
||||||
|
text.format = "org.matrix.custom.html";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!room->reply().isEmpty()) {
|
||||||
|
auto related = room->relatedInfo(room->reply());
|
||||||
|
|
||||||
|
QString body;
|
||||||
|
bool firstLine = true;
|
||||||
|
for (const auto &line : related.quoted_body.split("\n")) {
|
||||||
|
if (firstLine) {
|
||||||
|
firstLine = false;
|
||||||
|
body = QString("> <%1> %2\n").arg(related.quoted_user).arg(line);
|
||||||
|
} else {
|
||||||
|
body = QString("%1\n> %2\n").arg(body).arg(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
text.body = QString("%1\n%2").arg(body).arg(msg).toStdString();
|
||||||
|
|
||||||
|
// NOTE(Nico): rich replies always need a formatted_body!
|
||||||
|
text.format = "org.matrix.custom.html";
|
||||||
|
if (ChatPage::instance()->userSettings()->markdown())
|
||||||
|
text.formatted_body =
|
||||||
|
utils::getFormattedQuoteBody(related, utils::markdownToHtml(msg))
|
||||||
|
.toStdString();
|
||||||
|
else
|
||||||
|
text.formatted_body =
|
||||||
|
utils::getFormattedQuoteBody(related, msg.toHtmlEscaped()).toStdString();
|
||||||
|
|
||||||
|
text.relates_to.in_reply_to.event_id = related.related_event;
|
||||||
|
room->resetReply();
|
||||||
|
}
|
||||||
|
|
||||||
|
room->sendMessageEvent(text, mtx::events::EventType::RoomMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
InputBar::emote(QString msg)
|
||||||
|
{
|
||||||
|
auto html = utils::markdownToHtml(msg);
|
||||||
|
|
||||||
|
mtx::events::msg::Emote emote;
|
||||||
|
emote.body = msg.trimmed().toStdString();
|
||||||
|
|
||||||
|
if (html != msg.trimmed().toHtmlEscaped() &&
|
||||||
|
ChatPage::instance()->userSettings()->markdown()) {
|
||||||
|
emote.formatted_body = html.toStdString();
|
||||||
|
emote.format = "org.matrix.custom.html";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!room->reply().isEmpty()) {
|
||||||
|
emote.relates_to.in_reply_to.event_id = room->reply().toStdString();
|
||||||
|
room->resetReply();
|
||||||
|
}
|
||||||
|
|
||||||
|
room->sendMessageEvent(emote, mtx::events::EventType::RoomMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
InputBar::command(QString command, QString args)
|
||||||
|
{
|
||||||
|
if (command == "me") {
|
||||||
|
emote(args);
|
||||||
|
} else if (command == "join") {
|
||||||
|
ChatPage::instance()->joinRoom(args);
|
||||||
|
} else if (command == "invite") {
|
||||||
|
ChatPage::instance()->inviteUser(args.section(' ', 0, 0), args.section(' ', 1, -1));
|
||||||
|
} else if (command == "kick") {
|
||||||
|
ChatPage::instance()->kickUser(args.section(' ', 0, 0), args.section(' ', 1, -1));
|
||||||
|
} else if (command == "ban") {
|
||||||
|
ChatPage::instance()->banUser(args.section(' ', 0, 0), args.section(' ', 1, -1));
|
||||||
|
} else if (command == "unban") {
|
||||||
|
ChatPage::instance()->unbanUser(args.section(' ', 0, 0), args.section(' ', 1, -1));
|
||||||
|
} else if (command == "roomnick") {
|
||||||
|
mtx::events::state::Member member;
|
||||||
|
member.display_name = args.toStdString();
|
||||||
|
member.avatar_url =
|
||||||
|
cache::avatarUrl(room->roomId(),
|
||||||
|
QString::fromStdString(http::client()->user_id().to_string()))
|
||||||
|
.toStdString();
|
||||||
|
member.membership = mtx::events::state::Membership::Join;
|
||||||
|
|
||||||
|
http::client()->send_state_event(
|
||||||
|
room->roomId().toStdString(),
|
||||||
|
http::client()->user_id().to_string(),
|
||||||
|
member,
|
||||||
|
[](mtx::responses::EventId, mtx::http::RequestErr err) {
|
||||||
|
if (err)
|
||||||
|
nhlog::net()->error("Failed to set room displayname: {}",
|
||||||
|
err->matrix_error.error);
|
||||||
|
});
|
||||||
|
} else if (command == "shrug") {
|
||||||
|
message("¯\\_(ツ)_/¯" + (args.isEmpty() ? "" : " " + args));
|
||||||
|
} else if (command == "fliptable") {
|
||||||
|
message("(╯°□°)╯︵ ┻━┻");
|
||||||
|
} else if (command == "unfliptable") {
|
||||||
|
message(" ┯━┯╭( º _ º╭)");
|
||||||
|
} else if (command == "sovietflip") {
|
||||||
|
message("ノ┬─┬ノ ︵ ( \\o°o)\\");
|
||||||
|
} else if (command == "clear-timeline") {
|
||||||
|
room->clearTimeline();
|
||||||
|
} else if (command == "rotate-megolm-session") {
|
||||||
|
cache::dropOutboundMegolmSession(room->roomId().toStdString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <deque>
|
||||||
|
|
||||||
class TimelineModel;
|
class TimelineModel;
|
||||||
|
|
||||||
class InputBar : public QObject {
|
class InputBar : public QObject
|
||||||
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -15,11 +17,20 @@ public:
|
|||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void send();
|
void send();
|
||||||
bool paste(bool fromMouse);
|
void paste(bool fromMouse);
|
||||||
void updateState(int selectionStart, int selectionEnd, int cursorPosition, QString text);
|
void updateState(int selectionStart, int selectionEnd, int cursorPosition, QString text);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void insertText(QString text);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void message(QString body);
|
||||||
|
void emote(QString body);
|
||||||
|
void command(QString name, QString args);
|
||||||
|
|
||||||
TimelineModel *room;
|
TimelineModel *room;
|
||||||
QString text;
|
QString text;
|
||||||
|
std::deque<QString> history_;
|
||||||
|
std::size_t history_index_ = 0;
|
||||||
int selectionStart = 0, selectionEnd = 0, cursorPosition = 0;
|
int selectionStart = 0, selectionEnd = 0, cursorPosition = 0;
|
||||||
};
|
};
|
||||||
|
@ -1567,4 +1567,3 @@ TimelineModel::roomTopic() const
|
|||||||
return utils::replaceEmoji(utils::linkifyMessage(
|
return utils::replaceEmoji(utils::linkifyMessage(
|
||||||
utils::escapeBlacklistedHtml(QString::fromStdString(info[room_id_].topic))));
|
utils::escapeBlacklistedHtml(QString::fromStdString(info[room_id_].topic))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -474,81 +474,6 @@ TimelineViewManager::initWithMessages(const std::vector<QString> &roomIds)
|
|||||||
addRoom(roomId);
|
addRoom(roomId);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
TimelineViewManager::queueTextMessage(const QString &msg)
|
|
||||||
{
|
|
||||||
if (!timeline_)
|
|
||||||
return;
|
|
||||||
|
|
||||||
mtx::events::msg::Text text = {};
|
|
||||||
text.body = msg.trimmed().toStdString();
|
|
||||||
|
|
||||||
if (ChatPage::instance()->userSettings()->markdown()) {
|
|
||||||
text.formatted_body = utils::markdownToHtml(msg).toStdString();
|
|
||||||
|
|
||||||
// Don't send formatted_body, when we don't need to
|
|
||||||
if (text.formatted_body.find("<") == std::string::npos)
|
|
||||||
text.formatted_body = "";
|
|
||||||
else
|
|
||||||
text.format = "org.matrix.custom.html";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!timeline_->reply().isEmpty()) {
|
|
||||||
auto related = timeline_->relatedInfo(timeline_->reply());
|
|
||||||
|
|
||||||
QString body;
|
|
||||||
bool firstLine = true;
|
|
||||||
for (const auto &line : related.quoted_body.split("\n")) {
|
|
||||||
if (firstLine) {
|
|
||||||
firstLine = false;
|
|
||||||
body = QString("> <%1> %2\n").arg(related.quoted_user).arg(line);
|
|
||||||
} else {
|
|
||||||
body = QString("%1\n> %2\n").arg(body).arg(line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
text.body = QString("%1\n%2").arg(body).arg(msg).toStdString();
|
|
||||||
|
|
||||||
// NOTE(Nico): rich replies always need a formatted_body!
|
|
||||||
text.format = "org.matrix.custom.html";
|
|
||||||
if (ChatPage::instance()->userSettings()->markdown())
|
|
||||||
text.formatted_body =
|
|
||||||
utils::getFormattedQuoteBody(related, utils::markdownToHtml(msg))
|
|
||||||
.toStdString();
|
|
||||||
else
|
|
||||||
text.formatted_body =
|
|
||||||
utils::getFormattedQuoteBody(related, msg.toHtmlEscaped()).toStdString();
|
|
||||||
|
|
||||||
text.relates_to.in_reply_to.event_id = related.related_event;
|
|
||||||
timeline_->resetReply();
|
|
||||||
}
|
|
||||||
|
|
||||||
timeline_->sendMessageEvent(text, mtx::events::EventType::RoomMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
TimelineViewManager::queueEmoteMessage(const QString &msg)
|
|
||||||
{
|
|
||||||
auto html = utils::markdownToHtml(msg);
|
|
||||||
|
|
||||||
mtx::events::msg::Emote emote;
|
|
||||||
emote.body = msg.trimmed().toStdString();
|
|
||||||
|
|
||||||
if (html != msg.trimmed().toHtmlEscaped() &&
|
|
||||||
ChatPage::instance()->userSettings()->markdown()) {
|
|
||||||
emote.formatted_body = html.toStdString();
|
|
||||||
emote.format = "org.matrix.custom.html";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!timeline_->reply().isEmpty()) {
|
|
||||||
emote.relates_to.in_reply_to.event_id = timeline_->reply().toStdString();
|
|
||||||
timeline_->resetReply();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (timeline_)
|
|
||||||
timeline_->sendMessageEvent(emote, mtx::events::EventType::RoomMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
TimelineViewManager::queueReactionMessage(const QString &reactedEvent, const QString &reactionKey)
|
TimelineViewManager::queueReactionMessage(const QString &reactedEvent, const QString &reactionKey)
|
||||||
{
|
{
|
||||||
|
@ -104,8 +104,6 @@ public slots:
|
|||||||
void setHistoryView(const QString &room_id);
|
void setHistoryView(const QString &room_id);
|
||||||
void updateColorPalette();
|
void updateColorPalette();
|
||||||
void queueReactionMessage(const QString &reactedEvent, const QString &reactionKey);
|
void queueReactionMessage(const QString &reactedEvent, const QString &reactionKey);
|
||||||
void queueTextMessage(const QString &msg);
|
|
||||||
void queueEmoteMessage(const QString &msg);
|
|
||||||
void queueImageMessage(const QString &roomid,
|
void queueImageMessage(const QString &roomid,
|
||||||
const QString &filename,
|
const QString &filename,
|
||||||
const std::optional<mtx::crypto::EncryptedFile> &file,
|
const std::optional<mtx::crypto::EncryptedFile> &file,
|
||||||
@ -139,12 +137,6 @@ public slots:
|
|||||||
|
|
||||||
void updateEncryptedDescriptions();
|
void updateEncryptedDescriptions();
|
||||||
|
|
||||||
void clearCurrentRoomTimeline()
|
|
||||||
{
|
|
||||||
if (timeline_)
|
|
||||||
timeline_->clearTimeline();
|
|
||||||
}
|
|
||||||
|
|
||||||
void enableBackButton()
|
void enableBackButton()
|
||||||
{
|
{
|
||||||
if (isNarrowView_)
|
if (isNarrowView_)
|
||||||
|
Loading…
Reference in New Issue
Block a user