matrixion/src/timeline/InputBar.cpp

199 lines
7 KiB
C++
Raw Normal View History

2020-11-01 01:24:07 +03:00
#include "InputBar.h"
#include <QClipboard>
#include <QGuiApplication>
#include <QMimeData>
2020-11-09 05:12:37 +03:00
#include <mtx/responses/common.hpp>
#include "Cache.h"
#include "ChatPage.h"
2020-11-01 01:24:07 +03:00
#include "Logging.h"
2020-11-09 05:12:37 +03:00
#include "MatrixClient.h"
#include "TimelineModel.h"
#include "UserSettingsPage.h"
#include "Utils.h"
static constexpr size_t INPUT_HISTORY_SIZE = 10;
2020-11-01 01:24:07 +03:00
2020-11-09 05:12:37 +03:00
void
2020-11-01 01:24:07 +03:00
InputBar::paste(bool fromMouse)
{
const QMimeData *md = nullptr;
if (fromMouse) {
if (QGuiApplication::clipboard()->supportsSelection()) {
md = QGuiApplication::clipboard()->mimeData(QClipboard::Selection);
}
} else {
md = QGuiApplication::clipboard()->mimeData(QClipboard::Clipboard);
}
if (!md)
2020-11-09 05:12:37 +03:00
return;
2020-11-01 01:24:07 +03:00
if (md->hasImage()) {
2020-11-09 05:12:37 +03:00
} else if (md->hasText()) {
emit insertText(md->text());
2020-11-01 01:24:07 +03:00
} else {
nhlog::ui()->debug("formats: {}", md->formats().join(", ").toStdString());
}
}
void
InputBar::updateState(int selectionStart_, int selectionEnd_, int cursorPosition_, QString text_)
{
selectionStart = selectionStart_;
selectionEnd = selectionEnd_;
cursorPosition = cursorPosition_;
text = text_;
}
void
InputBar::send()
{
2020-11-09 05:12:37 +03:00
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);
}
2020-11-01 01:24:07 +03:00
nhlog::ui()->debug("Send: {}", text.toStdString());
}
2020-11-09 05:12:37 +03:00
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());
}
}