summary refs log tree commit diff
path: root/src/timeline
diff options
context:
space:
mode:
Diffstat (limited to 'src/timeline')
-rw-r--r--src/timeline/InputBar.cpp160
-rw-r--r--src/timeline/InputBar.h15
-rw-r--r--src/timeline/TimelineModel.cpp1
-rw-r--r--src/timeline/TimelineViewManager.cpp75
-rw-r--r--src/timeline/TimelineViewManager.h8
5 files changed, 169 insertions, 90 deletions
diff --git a/src/timeline/InputBar.cpp b/src/timeline/InputBar.cpp
index d128631d..dcd4a106 100644
--- a/src/timeline/InputBar.cpp
+++ b/src/timeline/InputBar.cpp
@@ -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());
+        }
+}
diff --git a/src/timeline/InputBar.h b/src/timeline/InputBar.h
index 78b06960..f3a38c2e 100644
--- a/src/timeline/InputBar.h
+++ b/src/timeline/InputBar.h
@@ -1,10 +1,12 @@
 #pragma once
 
 #include <QObject>
+#include <deque>
 
 class TimelineModel;
 
-class InputBar : public QObject {
+class InputBar : public QObject
+{
         Q_OBJECT
 
 public:
@@ -15,11 +17,20 @@ public:
 
 public slots:
         void send();
-        bool paste(bool fromMouse);
+        void paste(bool fromMouse);
         void updateState(int selectionStart, int selectionEnd, int cursorPosition, QString text);
 
+signals:
+        void insertText(QString text);
+
 private:
+        void message(QString body);
+        void emote(QString body);
+        void command(QString name, QString args);
+
         TimelineModel *room;
         QString text;
+        std::deque<QString> history_;
+        std::size_t history_index_ = 0;
         int selectionStart = 0, selectionEnd = 0, cursorPosition = 0;
 };
diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp
index aeb4e8f5..8b80ea51 100644
--- a/src/timeline/TimelineModel.cpp
+++ b/src/timeline/TimelineModel.cpp
@@ -1567,4 +1567,3 @@ TimelineModel::roomTopic() const
                 return utils::replaceEmoji(utils::linkifyMessage(
                   utils::escapeBlacklistedHtml(QString::fromStdString(info[room_id_].topic))));
 }
-
diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp
index 3b80d020..f949498d 100644
--- a/src/timeline/TimelineViewManager.cpp
+++ b/src/timeline/TimelineViewManager.cpp
@@ -475,81 +475,6 @@ TimelineViewManager::initWithMessages(const std::vector<QString> &roomIds)
 }
 
 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
 TimelineViewManager::queueReactionMessage(const QString &reactedEvent, const QString &reactionKey)
 {
         if (!timeline_)
diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h
index f330d870..02e0e132 100644
--- a/src/timeline/TimelineViewManager.h
+++ b/src/timeline/TimelineViewManager.h
@@ -104,8 +104,6 @@ public slots:
         void setHistoryView(const QString &room_id);
         void updateColorPalette();
         void queueReactionMessage(const QString &reactedEvent, const QString &reactionKey);
-        void queueTextMessage(const QString &msg);
-        void queueEmoteMessage(const QString &msg);
         void queueImageMessage(const QString &roomid,
                                const QString &filename,
                                const std::optional<mtx::crypto::EncryptedFile> &file,
@@ -139,12 +137,6 @@ public slots:
 
         void updateEncryptedDescriptions();
 
-        void clearCurrentRoomTimeline()
-        {
-                if (timeline_)
-                        timeline_->clearTimeline();
-        }
-
         void enableBackButton()
         {
                 if (isNarrowView_)