|
|
|
@ -4,9 +4,19 @@ |
|
|
|
|
#include <QGuiApplication> |
|
|
|
|
#include <QMimeData> |
|
|
|
|
|
|
|
|
|
#include <mtx/responses/common.hpp> |
|
|
|
|
|
|
|
|
|
#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; |
|
|
|
|
|
|
|
|
|
bool |
|
|
|
|
void |
|
|
|
|
InputBar::paste(bool fromMouse) |
|
|
|
|
{ |
|
|
|
|
const QMimeData *md = nullptr; |
|
|
|
@ -20,13 +30,13 @@ InputBar::paste(bool fromMouse) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!md) |
|
|
|
|
return false; |
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
if (md->hasImage()) { |
|
|
|
|
return true; |
|
|
|
|
} else if (md->hasText()) { |
|
|
|
|
emit insertText(md->text()); |
|
|
|
|
} else { |
|
|
|
|
nhlog::ui()->debug("formats: {}", md->formats().join(", ").toStdString()); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -42,5 +52,147 @@ InputBar::updateState(int selectionStart_, int selectionEnd_, int cursorPosition |
|
|
|
|
void |
|
|
|
|
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()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|